123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- /*
- * Copyright (c) 2006-2017 DMDirc Developers
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
- * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
- package com.dmdirc.addons.dcc;
-
- import com.dmdirc.addons.dcc.events.DccChatRequestEvent;
- import com.dmdirc.addons.dcc.events.DccChatStartingEvent;
- import com.dmdirc.addons.dcc.events.DccSendRequestEvent;
- import com.dmdirc.addons.dcc.io.DCC;
- import com.dmdirc.addons.dcc.io.DCCChat;
- import com.dmdirc.addons.dcc.io.DCCTransfer;
- import com.dmdirc.addons.dcc.kde.KFileChooser;
- import com.dmdirc.addons.dcc.ui.PlaceholderPanel;
- import com.dmdirc.addons.dcc.ui.TransferPanel;
- import com.dmdirc.addons.ui_swing.SwingWindowFactory;
- import com.dmdirc.addons.ui_swing.components.frames.ComponentFrameFactory;
- import com.dmdirc.addons.ui_swing.components.frames.TextFrame;
- import com.dmdirc.addons.ui_swing.dialogs.StandardQuestionDialog;
- import com.dmdirc.addons.ui_swing.injection.MainWindow;
- import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
- import com.dmdirc.commandline.CommandLineOptionsModule.DirectoryType;
- import com.dmdirc.commandparser.parsers.CommandParser;
- import com.dmdirc.commandparser.parsers.GlobalCommandParser;
- import com.dmdirc.config.GlobalConfig;
- import com.dmdirc.config.prefs.PluginPreferencesCategory;
- import com.dmdirc.config.prefs.PreferencesCategory;
- import com.dmdirc.config.prefs.PreferencesDialogModel;
- import com.dmdirc.config.prefs.PreferencesSetting;
- import com.dmdirc.config.prefs.PreferencesType;
- import com.dmdirc.events.ClientPrefsOpenedEvent;
- import com.dmdirc.events.ServerCtcpEvent;
- import com.dmdirc.interfaces.CommandController;
- import com.dmdirc.interfaces.Connection;
- import com.dmdirc.events.eventbus.EventBus;
- import com.dmdirc.interfaces.User;
- import com.dmdirc.interfaces.WindowModel;
- import com.dmdirc.interfaces.config.AggregateConfigProvider;
- import com.dmdirc.interfaces.config.ConfigProvider;
- import com.dmdirc.interfaces.config.IdentityController;
- import com.dmdirc.parser.interfaces.Parser;
- import com.dmdirc.plugins.PluginDomain;
- import com.dmdirc.plugins.PluginInfo;
- import com.dmdirc.ui.WindowManager;
- import com.dmdirc.ui.input.TabCompleterFactory;
- import com.dmdirc.ui.messages.BackBufferFactory;
- import com.google.common.collect.Sets;
- import java.awt.Dialog;
- import java.awt.Window;
- import java.io.File;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.UnknownHostException;
- import java.util.Collections;
- import java.util.Set;
- import java.util.function.Supplier;
- import javax.inject.Inject;
- import javax.inject.Singleton;
- import javax.swing.JComponent;
- import javax.swing.JFileChooser;
- import javax.swing.JOptionPane;
- import net.engio.mbassy.listener.Handler;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import static com.dmdirc.util.LogUtils.USER_ERROR;
-
- /**
- * This plugin adds DCC to DMDirc.
- */
- @Singleton
- public class DCCManager {
-
- private static final Logger LOG = LoggerFactory.getLogger(DCCManager.class);
- private final BackBufferFactory backBufferFactory;
- /** Our DCC Container window. */
- private PlaceholderContainer container;
- /** Config manager to read settings from. */
- private final AggregateConfigProvider config;
- /** Window Management. */
- private final WindowManager windowManager;
- /** The command controller to use. */
- private final CommandController commandController;
- /** The factory to use for tab completers. */
- private final TabCompleterFactory tabCompleterFactory;
- /** The client's main window that will parent any new windows. */
- private final Window mainWindow;
- /** The configuration domain to use. */
- private final String domain;
- /** The bus to dispatch events on. */
- private final EventBus eventBus;
- /** Plugin info. */
- private final PluginInfo pluginInfo;
-
- /**
- * Creates a new instance of this plugin.
- */
- @Inject
- public DCCManager(
- @MainWindow final Window mainWindow,
- @PluginDomain(DCCPlugin.class) final PluginInfo pluginInfo,
- final IdentityController identityController,
- @GlobalConfig final AggregateConfigProvider globalConfig,
- final CommandController commandController,
- final WindowManager windowManager,
- final TabCompleterFactory tabCompleterFactory,
- final SwingWindowFactory windowFactory,
- final ComponentFrameFactory componentFrameFactory,
- final EventBus eventBus,
- final GlobalCommandParser commandParser,
- @Directory(DirectoryType.BASE) final String baseDirectory,
- final BackBufferFactory backBufferFactory) {
- this.mainWindow = mainWindow;
- this.windowManager = windowManager;
- this.commandController = commandController;
- this.tabCompleterFactory = tabCompleterFactory;
- this.pluginInfo = pluginInfo;
- this.domain = pluginInfo.getDomain();
- this.config = globalConfig;
- this.eventBus = eventBus;
- this.backBufferFactory = backBufferFactory;
-
- windowFactory.registerImplementation(new ComponentFrameWindowProvider(
- "com.dmdirc.addons.dcc.ui.PlaceholderPanel", componentFrameFactory,
- commandParser, PlaceholderPanel::new));
- windowFactory.registerImplementation(new ComponentFrameWindowProvider(
- "com.dmdirc.addons.dcc.ui.TransferPanel", componentFrameFactory,
- commandParser, () -> new TransferPanel(container, eventBus)));
-
- final ConfigProvider defaults = identityController.getAddonSettings();
- defaults.setOption(domain, "receive.savelocation",
- baseDirectory + "downloads" + File.separator);
- }
-
- @Handler
- public void handlePrefsOpened(final ClientPrefsOpenedEvent event) {
- final PreferencesDialogModel manager = event.getModel();
- final PreferencesCategory general = new PluginPreferencesCategory(
- pluginInfo, "DCC", "", "category-dcc");
- final PreferencesCategory firewall = new PluginPreferencesCategory(
- pluginInfo, "Firewall", "");
- final PreferencesCategory sending = new PluginPreferencesCategory(
- pluginInfo, "Sending", "");
- final PreferencesCategory receiving = new PluginPreferencesCategory(
- pluginInfo, "Receiving", "");
-
- manager.getCategory("Plugins").addSubCategory(general.setInlineAfter());
- general.addSubCategory(firewall.setInline());
- general.addSubCategory(sending.setInline());
- general.addSubCategory(receiving.setInline());
-
- firewall.addSetting(
- new PreferencesSetting(PreferencesType.TEXT, pluginInfo.getDomain(), "firewall.ip",
- "Forced IP", "What IP should be sent as our IP (Blank = work it out)",
- manager.getConfigManager(), manager.getIdentity()));
- firewall.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN, pluginInfo.getDomain(),
- "firewall.ports.usePortRange", "Use Port Range",
- "Useful if you have a firewall that only forwards specific " + "ports",
- manager.getConfigManager(), manager.getIdentity()));
- firewall.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
- pluginInfo.getDomain(), "firewall.ports.startPort", "Start Port",
- "Port to try to listen on first", manager.getConfigManager(),
- manager.getIdentity()));
- firewall.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
- pluginInfo.getDomain(), "firewall.ports.endPort", "End Port",
- "Port to try to listen on last", manager.getConfigManager(),
- manager.getIdentity()));
- receiving.addSetting(new PreferencesSetting(PreferencesType.DIRECTORY,
- pluginInfo.getDomain(), "receive.savelocation", "Default save location",
- "Where the save as window defaults to?",
- manager.getConfigManager(), manager.getIdentity()));
- sending.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- pluginInfo.getDomain(), "send.reverse", "Reverse DCC",
- "With reverse DCC, the sender connects rather than "
- + "listens like normal dcc", manager.getConfigManager(),
- manager.getIdentity()));
- sending.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- pluginInfo.getDomain(), "send.forceturbo", "Use Turbo DCC",
- "Turbo DCC doesn't wait for ack packets. this is "
- + "faster but not always supported.",
- manager.getConfigManager(), manager.getIdentity()));
- receiving.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
- pluginInfo.getDomain(), "receive.reverse.sendtoken",
- "Send token in reverse receive",
- "If you have problems with reverse dcc receive resume,"
- + " try toggling this.", manager.getConfigManager(),
- manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
- pluginInfo.getDomain(), "send.blocksize", "Blocksize to use for DCC",
- "Change the block size for send/receive, this can "
- + "sometimes speed up transfers.", manager.getConfigManager(),
- manager.getIdentity()));
- general.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN, pluginInfo.getDomain(),
- "general.percentageInTitle", "Show percentage of transfers in the window title",
- "Show the current percentage of transfers in the DCC window " + "title",
- manager.getConfigManager(), manager.getIdentity()));
- }
-
- public String getDomain() {
- return domain;
- }
-
- /**
- * Ask the location to save a file, then start the download.
- *
- * @param nickname Person this dcc is from.
- * @param send The DCCSend to save for.
- * @param parser The parser this send was received on
- * @param reverse Is this a reverse dcc?
- * @param token Token used in reverse dcc.
- */
- public void saveFile(final String nickname, final DCCTransfer send,
- final Parser parser, final boolean reverse, final String token) {
- // New thread to ask the user where to save in to stop us locking the UI
- new Thread(() -> {
- final JFileChooser jc = KFileChooser.getFileChooser(config, this,
- config.getOption(getDomain(), "receive.savelocation"));
- final int result;
- if (config.getOptionBool(getDomain(), "receive.autoaccept")) {
- result = JFileChooser.APPROVE_OPTION;
- } else {
- result = showFileChooser(send, jc);
- }
- if (result != JFileChooser.APPROVE_OPTION) {
- return;
- }
- send.setFileName(jc.getSelectedFile().getPath());
- if (!handleExists(send, jc, nickname, parser, reverse, token)) {
- return;
- }
- final boolean resume = handleResume(jc);
- if (reverse && !token.isEmpty()) {
- final TransferContainer container1 = new TransferContainer(this, send,
- config, backBufferFactory, "*Receive: " + nickname, nickname, null,
- eventBus);
- windowManager.addWindow(getContainer(), container1);
- send.setToken(token);
- if (resume) {
- if (config.getOptionBool(getDomain(),
- "receive.reverse.sendtoken")) {
- parser.sendCTCP(nickname, "DCC", "RESUME "
- + send.getShortFileName() + " 0 "
- + jc.getSelectedFile().length() + ' '
- + token);
- } else {
- parser.sendCTCP(nickname, "DCC", "RESUME "
- + send.getShortFileName() + " 0 "
- + jc.getSelectedFile().length());
- }
- } else {
- if (listen(send)) {
- parser.sendCTCP(nickname, "DCC", "SEND "
- + send.getShortFileName() + ' '
- + DCC.ipToLong(getListenIP(parser))
- + ' ' + send.getPort() + ' '
- + send.getFileSize() + ' ' + token);
- }
- }
- } else {
- final TransferContainer container1 = new TransferContainer(this, send,
- config, backBufferFactory, "Receive: " + nickname, nickname, null,
- eventBus);
- windowManager.addWindow(getContainer(), container1);
- if (resume) {
- parser.sendCTCP(nickname, "DCC", "RESUME "
- + send.getShortFileName() + ' '
- + send.getPort() + ' '
- + jc.getSelectedFile().length());
- } else {
- send.connect();
- }
- }
- }, "saveFileThread: " + send.getShortFileName()).start();
- }
-
- /**
- * Checks if the selected file exists and prompts the user as required.
- *
- * @param send DCC Transfer
- * @param jc File chooser
- * @param nickname Remote nickname
- * @param parser Parser
- * @param reverse Reverse DCC?
- * @param token DCC token
- *
- * @return true if the user wants to continue, false if they wish to abort
- */
- private boolean handleExists(final DCCTransfer send, final JFileChooser jc,
- final String nickname, final Parser parser, final boolean reverse,
- final String token) {
- if (jc.getSelectedFile().exists() && send.getFileSize() > -1
- && send.getFileSize() <= jc.getSelectedFile().length()) {
- if (config.getOptionBool(getDomain(), "receive.autoaccept")) {
- return false;
- } else {
- JOptionPane.showMessageDialog(
- mainWindow,
- "This file has already "
- + "been completed, or is longer than the file you are "
- + "receiving.\nPlease choose a different file.",
- "Problem with selected file",
- JOptionPane.ERROR_MESSAGE);
- saveFile(nickname, send, parser, reverse, token);
- return false;
- }
- }
- return true;
- }
-
- /**
- * Prompts the user to resume a transfer if required.
- *
- * @param jc File chooser
- *
- * @return true if the user wants to continue the transfer false otherwise
- */
- private boolean handleResume(final JFileChooser jc) {
- if (jc.getSelectedFile().exists()) {
- if (config.getOptionBool(getDomain(), "receive.autoaccept")) {
- return true;
- } else {
- final int result = JOptionPane.showConfirmDialog(
- mainWindow, "This file exists already"
- + ", do you want to resume an exisiting download?",
- "Resume Download?", JOptionPane.YES_NO_OPTION);
- return result == JOptionPane.YES_OPTION;
- }
- }
- return false;
- }
-
- /**
- * Sets up and display a file chooser.
- *
- * @param send DCCTransfer object sending the file
- * @param jc File chooser
- *
- * @return the return state of the file chooser on popdown:
- * <ul>
- * <li>JFileChooser.CANCEL_OPTION
- * <li>JFileChooser.APPROVE_OPTION
- * <li>JFileChooser.ERROR_OPTION if an error occurs or the dialog is dismissed
- * </ul>
- */
- private int showFileChooser(final DCCTransfer send, final JFileChooser jc) {
- jc.setDialogTitle("Save " + send.getShortFileName() + " As - DMDirc");
- jc.setFileSelectionMode(JFileChooser.FILES_ONLY);
- jc.setMultiSelectionEnabled(false);
- jc.setSelectedFile(new File(send.getFileName()));
- return jc.showSaveDialog(mainWindow);
- }
-
- /**
- * Make the given DCC start listening. This will either call dcc.listen() or
- * dcc.listen(startPort, endPort) depending on config.
- *
- * @param dcc DCC to start listening.
- *
- * @return True if Socket was opened.
- */
- protected boolean listen(final DCC dcc) {
- final boolean usePortRange = config.
- getOptionBool(getDomain(), "firewall.ports.usePortRange");
- try {
- if (usePortRange) {
- final int startPort = config.getOptionInt(getDomain(), "firewall.ports.startPort");
- final int endPort = config.getOptionInt(getDomain(), "firewall.ports.endPort");
- dcc.listen(startPort, endPort);
- } else {
- dcc.listen();
- }
- return true;
- } catch (IOException ioe) {
- return false;
- }
- }
-
- @Handler
- public void handleServerCtctpEvent(final ServerCtcpEvent event) {
- final boolean autoAccept = config.getOptionBool(getDomain(), "receive.autoaccept");
- final String[] ctcpData = event.getContent().split(" ");
- if (!"DCC".equalsIgnoreCase(event.getType())) {
- return;
- }
- switch (event.getType().toLowerCase()) {
- case "chat":
- if (ctcpData.length > 3) {
- handleChat(autoAccept, ctcpData, event.getUser(), event.getConnection());
- }
- break;
- case "send":
- if (ctcpData.length > 3) {
- handleSend(autoAccept, ctcpData, event.getUser(), event.getConnection());
- }
- break;
- case "resume":
- //Fallthrough
- case "accept":
- if (ctcpData.length > 2) {
- handleReceive(ctcpData, event.getUser(), event.getConnection());
- }
- break;
- default:
- break;
- }
- }
-
- /**
- * Handles a DCC chat request.
- *
- * @param dontAsk Don't ask any questions, assume yes.
- * @param ctcpData CTCP data bits
- * @param client Client receiving DCC
- * @param connection Connection DCC received on
- */
- private void handleChat(final boolean dontAsk, final String[] ctcpData,
- final User client, final Connection connection) {
- final String nickname = client.getNickname();
- if (dontAsk) {
- handleDCCChat(connection.getParser().get(), nickname, ctcpData);
- } else {
- eventBus.publish(new DccChatRequestEvent(connection, nickname));
- new StandardQuestionDialog(mainWindow, Dialog.ModalityType.APPLICATION_MODAL,
- "DCC Chat Request", "User " + nickname + " on " + connection.getAddress()
- + " would like to start a DCC Chat with you.\n\nDo you want to continue?",
- () -> handleDCCChat(connection.getParser().get(), nickname, ctcpData)).display();
- }
- }
-
- void handleDCCChat(final Parser parser, final String nickname, final String[] ctcpData) {
- final long ipAddress;
- final int port;
- try {
- ipAddress = Long.parseLong(ctcpData[2]);
- port = Integer.parseInt(ctcpData[3]);
- } catch (NumberFormatException nfe) {
- return;
- }
- final DCCChat chat = new DCCChat();
- chat.setAddress(ipAddress, port);
- final String myNickname = parser.getLocalClient().getNickname();
- final DCCFrameContainer container = new ChatContainer(
- chat,
- config,
- backBufferFactory,
- commandController,
- "Chat: " + nickname,
- myNickname,
- nickname,
- tabCompleterFactory,
- eventBus);
- windowManager.addWindow(getContainer(), container);
- container.getEventBus().publishAsync(new DccChatStartingEvent(
- container, nickname, chat.getHost(), chat.getPort()));
- chat.connect();
- }
-
- /**
- * Handles a DCC send request.
- *
- * @param dontAsk Don't ask any questions, assume yes.
- * @param ctcpData CTCP data bits
- * @param client Client that received the DCC
- * @param connection Connection the DCC was received on
- */
- private void handleSend(final boolean dontAsk, final String[] ctcpData, final User client,
- final Connection connection) {
- final String nickname = client.getNickname();
- String tmpFilename;
- // Clients tend to put files with spaces in the name in ""
- final StringBuilder filenameBits = new StringBuilder();
- int i;
- final boolean quoted = ctcpData[1].startsWith("\"");
- if (quoted) {
- for (i = 1; i < ctcpData.length; i++) {
- String bit = ctcpData[i];
- if (i == 1) {
- bit = bit.substring(1);
- }
- if (bit.endsWith("\"")) {
- filenameBits.append(' ').append(bit.substring(0, bit.length() - 1));
- break;
- } else {
- filenameBits.append(' ').append(bit);
- }
- }
- tmpFilename = filenameBits.toString().trim();
- } else {
- tmpFilename = ctcpData[1];
- i = 1;
- }
-
- // Try to remove path names if sent.
- // Change file separatorChar from other OSs first
- if (File.separatorChar == '/') {
- tmpFilename = tmpFilename.replace('\\', File.separatorChar);
- } else {
- tmpFilename = tmpFilename.replace('/', File.separatorChar);
- }
- // Then get just the name of the file.
- final String filename = new File(tmpFilename).getName();
-
- final String ip = ctcpData[++i];
- final String port = ctcpData[++i];
- long size;
- if (ctcpData.length + 1 > i) {
- try {
- size = Integer.parseInt(ctcpData[++i]);
- } catch (NumberFormatException nfe) {
- size = -1;
- }
- } else {
- size = -1;
- }
- final String token = ctcpData.length - 1 > i
- && !"T".equals(ctcpData[i + 1]) ? ctcpData[++i] : "";
-
- // Ignore incorrect ports, or non-numeric IP/Port
- final long ipLong;
- final int portInt;
- try {
- portInt = Integer.parseInt(port);
- if (portInt > 65535 || portInt < 0) {
- return;
- }
- ipLong = Long.parseLong(ip);
- } catch (NumberFormatException nfe) {
- return;
- }
-
- if (DCCTransfer.findByToken(token) == null && !dontAsk &&
- (token.isEmpty() || "0".equals(port))) {
- // Make sure this is not a reverse DCC Send that we no longer care about.
- eventBus.publish(new DccSendRequestEvent(connection, nickname, filename));
- final long passedSize = size;
- new StandardQuestionDialog(mainWindow, Dialog.ModalityType.APPLICATION_MODAL,
- "DCC Send Request", "User " + nickname + " on " + connection.getAddress()
- + " would like to send you a file over DCC.\n\nFile: "
- + filename + "\n\nDo you want to continue?",
- () -> handleDCCSend(token, ipLong, portInt, filename, passedSize, nickname,
- connection.getParser().get())).display();
- }
- }
-
- void handleDCCSend(final String token, final long ip, final int port, final String filename,
- final long size, final String nickname, final Parser parser) {
- DCCTransfer send = DCCTransfer.findByToken(token);
- final boolean newSend = send == null;
- if (newSend) {
- send = new DCCTransfer(config.getOptionInt(getDomain(), "send.blocksize"));
- send.setTurbo(config.getOptionBool(getDomain(), "send.forceturbo"));
- } else {
- return;
- }
- send.setAddress(ip, port);
- send.setFileName(filename);
- send.setFileSize(size);
- saveFile(nickname, send, parser, port == 0, token);
- }
-
- /**
- * Handles a DCC chat request.
- *
- * @param ctcpData CTCP data bits
- * @param client Client receiving the DCC
- * @param connection Connection the DCC was received on
- */
- private void handleReceive(final String[] ctcpData, final User client,
- final Connection connection) {
- final String filename;
- // Clients tend to put files with spaces in the name in ""
- final StringBuilder filenameBits = new StringBuilder();
- int i;
- final boolean quoted = ctcpData[1].startsWith("\"");
- if (quoted) {
- for (i = 1; i < ctcpData.length; i++) {
- String bit = ctcpData[i];
- if (i == 1) {
- bit = bit.substring(1);
- }
- if (bit.endsWith("\"")) {
- filenameBits.append(' ')
- .append(bit.substring(0, bit.length() - 1));
- break;
- } else {
- filenameBits.append(' ').append(bit);
- }
- }
- filename = filenameBits.toString().trim();
- } else {
- filename = ctcpData[1];
- i = 1;
- }
-
- final int port;
- final int position;
- try {
- port = Integer.parseInt(ctcpData[++i]);
- position = Integer.parseInt(ctcpData[++i]);
- } catch (NumberFormatException nfe) {
- return;
- }
- final String token = ctcpData.length - 1 > i ? ' '
- + ctcpData[++i] : "";
-
- // Now look for a dcc that matches.
- for (DCCTransfer send : DCCTransfer.getTransfers()) {
- if (send.getPort() == port && new File(send.getFileName())
- .getName().equalsIgnoreCase(filename)) {
- if (!token.isEmpty() && !send.getToken().isEmpty() &&
- !token.equals(send.getToken())) {
- continue;
- }
- final Parser parser = connection.getParser().get();
- final String nick = client.getNickname();
- if ("resume".equalsIgnoreCase(ctcpData[0])) {
- parser.sendCTCP(nick, "DCC", "ACCEPT " + (quoted ? '"'
- + filename + '"' : filename) + ' ' + port + ' '
- + send.setFileStart(position) + token);
- } else {
- send.setFileStart(position);
- if (port == 0) {
- // Reverse dcc
- if (listen(send)) {
- if (send.getToken().isEmpty()) {
- parser.sendCTCP(nick, "DCC", "SEND "
- + (quoted ? '"' + filename
- + '"' : filename) + ' '
- + DCC.ipToLong(send.getHost())
- + ' ' + send.getPort()
- + ' ' + send.getFileSize());
- } else {
- parser.sendCTCP(nick, "DCC", "SEND "
- + (quoted ? '"' + filename
- + '"' : filename)
- + ' ' + DCC.ipToLong(send.getHost())
- + ' ' + send.getPort()
- + ' ' + send.getFileSize() + ' '
- + send.getToken());
- }
- }
- } else {
- send.connect();
- }
- }
- }
- }
- }
-
- /**
- * Retrieves the container for the placeholder.
- *
- * @since 0.6.4
- * @return This plugin's placeholder container
- */
- public synchronized PlaceholderContainer getContainer() {
- if (container == null) {
- createContainer();
- }
-
- return container;
- }
-
- /**
- * Removes the cached container.
- *
- * @since 0.6.4
- */
- public synchronized void removeContainer() {
- container = null;
- }
-
- /**
- * Create the container window.
- */
- protected void createContainer() {
- container = new PlaceholderContainer(this, config, backBufferFactory, mainWindow,
- windowManager, eventBus);
- windowManager.addWindow(container);
- }
-
- /**
- * Called when the plugin is loaded.
- */
- public void onLoad() {
- final File dir = new File(config.getOption(getDomain(),
- "receive.savelocation"));
- if (dir.exists()) {
- if (!dir.isDirectory()) {
- LOG.info(USER_ERROR, "Unable to create download dir (file exists instead)",
- new IllegalArgumentException("Directory is really a file"));
- }
- } else {
- try {
- dir.mkdirs();
- dir.createNewFile();
- } catch (IOException ex) {
- LOG.info(USER_ERROR, "Unable to create download dir",
- new IllegalArgumentException("Unable to create download dir"));
- }
- }
-
- eventBus.subscribe(this);
- }
-
- /**
- * Called when this plugin is Unloaded.
- */
- public synchronized void onUnload() {
- eventBus.unsubscribe(this);
- if (container != null) {
- container.close();
- }
- }
-
- /**
- * Get the IP Address we should send as our listening IP.
- *
- * @param parser Parser the IRC Parser where this dcc is initiated
- *
- * @return The IP Address we should send as our listening IP.
- */
- public String getListenIP(final Parser parser) {
- final String configIP = config.getOption(getDomain(), "firewall.ip");
- if (!configIP.isEmpty()) {
- try {
- return InetAddress.getByName(configIP).getHostAddress();
- } catch (UnknownHostException ex) { //NOPMD - handled below
- //Continue below
- }
- }
- if (parser != null) {
- final String myHost = parser.getLocalClient().getHostname();
- if (!myHost.isEmpty()) {
- try {
- return InetAddress.getByName(myHost).getHostAddress();
- } catch (UnknownHostException e) { //NOPMD - handled below
- //Continue below
- }
- }
- }
- try {
- return InetAddress.getLocalHost().getHostAddress();
- } catch (UnknownHostException e) {
- // This is almost certainly not what we want, but we can't work out
- // the right one.
- return "127.0.0.1"; //NOPMD
- }
- }
-
- private static class ComponentFrameWindowProvider implements SwingWindowFactory.WindowProvider {
-
- private final String component;
- private final ComponentFrameFactory componentFrameFactory;
- private final CommandParser commandParser;
- private final Supplier<? extends JComponent> componentSupplier;
-
- ComponentFrameWindowProvider(final String component,
- final ComponentFrameFactory componentFrameFactory,
- final CommandParser commandParser,
- final Supplier<? extends JComponent> componentSupplier) {
- this.component = component;
- this.componentFrameFactory = componentFrameFactory;
- this.commandParser = commandParser;
- this.componentSupplier = componentSupplier;
- }
-
- @Override
- public TextFrame getWindow(final WindowModel container) {
- return componentFrameFactory.getComponentFrame(container, commandParser,
- Collections.singletonList(componentSupplier));
- }
-
- @Override
- public Set<String> getComponents() {
- return Sets.newHashSet(component);
- }
- }
-
- }
|