You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DCCPlugin.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. /*
  2. * Copyright (c) 2006-2010 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.dcc;
  23. import com.dmdirc.Main;
  24. import com.dmdirc.Server;
  25. import com.dmdirc.actions.ActionManager;
  26. import com.dmdirc.actions.CoreActionType;
  27. import com.dmdirc.actions.interfaces.ActionType;
  28. import com.dmdirc.addons.dcc.kde.KFileChooser;
  29. import com.dmdirc.addons.dcc.actions.DCCActions;
  30. import com.dmdirc.addons.ui_swing.components.frames.TextFrame;
  31. import com.dmdirc.addons.ui_swing.components.text.TextLabel;
  32. import com.dmdirc.commandparser.CommandManager;
  33. import com.dmdirc.config.Identity;
  34. import com.dmdirc.config.IdentityManager;
  35. import com.dmdirc.config.prefs.PreferencesCategory;
  36. import com.dmdirc.config.prefs.PreferencesManager;
  37. import com.dmdirc.config.prefs.PreferencesSetting;
  38. import com.dmdirc.config.prefs.PreferencesType;
  39. import com.dmdirc.interfaces.ActionListener;
  40. import com.dmdirc.logger.ErrorLevel;
  41. import com.dmdirc.logger.Logger;
  42. import com.dmdirc.parser.interfaces.ClientInfo;
  43. import com.dmdirc.parser.interfaces.Parser;
  44. import com.dmdirc.plugins.Plugin;
  45. import com.dmdirc.ui.WindowManager;
  46. import java.io.File;
  47. import java.io.IOException;
  48. import java.util.ArrayList;
  49. import java.util.List;
  50. import java.net.InetAddress;
  51. import java.net.UnknownHostException;
  52. import javax.swing.JFileChooser;
  53. import javax.swing.JFrame;
  54. import javax.swing.JOptionPane;
  55. /**
  56. * This plugin adds DCC to dmdirc.
  57. *
  58. * @author Shane 'Dataforce' McCormack
  59. */
  60. public final class DCCPlugin extends Plugin implements ActionListener {
  61. /** The DCCCommand we created. */
  62. private DCCCommand command;
  63. /** Our DCC Container window. */
  64. private DCCFrame container;
  65. /** Child Frames. */
  66. private final List<DCCFrame> childFrames = new ArrayList<DCCFrame>();
  67. /**
  68. * Creates a new instance of the DCC Plugin.
  69. */
  70. public DCCPlugin() {
  71. super();
  72. }
  73. /**
  74. * Ask a question, if the answer is the answer required, then recall handleProcessEvent.
  75. *
  76. * @param question Question to ask
  77. * @param title Title of question dialog
  78. * @param desiredAnswer Answer required
  79. * @param type Actiontype to pass back
  80. * @param format StringBuffer to pass back
  81. * @param arguments arguments to pass back
  82. */
  83. public void askQuestion(final String question, final String title, final int desiredAnswer, final ActionType type, final StringBuffer format, final Object... arguments) {
  84. // New thread to ask the question in to stop us locking the UI
  85. final Thread questionThread = new Thread(new Runnable() {
  86. /** {@inheritDoc} */
  87. @Override
  88. public void run() {
  89. int result = JOptionPane.showConfirmDialog(null, question, title, JOptionPane.YES_NO_OPTION);
  90. if (result == desiredAnswer) {
  91. handleProcessEvent(type, format, true, arguments);
  92. }
  93. }
  94. }, "QuestionThread: " + title);
  95. // Start the thread
  96. questionThread.start();
  97. }
  98. /**
  99. * Ask the location to save a file, then start the download.
  100. *
  101. * @param nickname Person this dcc is from.
  102. * @param send The DCCSend to save for.
  103. * @param parser The parser this send was received on
  104. * @param reverse Is this a reverse dcc?
  105. * @param sendFilename The name of the file which is being received
  106. * @param token Token used in reverse dcc.
  107. */
  108. public void saveFile(final String nickname, final DCCSend send, final Parser parser, final boolean reverse, final String sendFilename, final String token) {
  109. // New thread to ask the user where to save in to stop us locking the UI
  110. final Thread dccThread = new Thread(new Runnable() {
  111. /** {@inheritDoc} */
  112. @Override
  113. public void run() {
  114. final JFileChooser jc = KFileChooser.getFileChooser(DCCPlugin.this, IdentityManager.getGlobalConfig().getOption(getDomain(), "receive.savelocation"));
  115. jc.setDialogTitle("Save " + sendFilename + " As - DMDirc");
  116. jc.setFileSelectionMode(JFileChooser.FILES_ONLY);
  117. jc.setMultiSelectionEnabled(false);
  118. jc.setSelectedFile(new File(send.getFileName()));
  119. int result;
  120. if (IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "receive.autoaccept")) {
  121. result = JFileChooser.APPROVE_OPTION;
  122. } else {
  123. result = jc.showSaveDialog((JFrame) Main.getUI().getMainWindow());
  124. }
  125. if (result == JFileChooser.APPROVE_OPTION) {
  126. send.setFileName(jc.getSelectedFile().getPath());
  127. boolean resume = false;
  128. if (jc.getSelectedFile().exists()) {
  129. if (send.getFileSize() > -1 && send.getFileSize() <= jc.getSelectedFile().length()) {
  130. if (IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "receive.autoaccept")) {
  131. return;
  132. } else {
  133. JOptionPane.showMessageDialog((JFrame) Main.getUI().getMainWindow(), "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);
  134. saveFile(nickname, send, parser, reverse, sendFilename, token);
  135. return;
  136. }
  137. } else {
  138. if (IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "receive.autoaccept")) {
  139. resume = true;
  140. } else {
  141. result = JOptionPane.showConfirmDialog((JFrame) Main.getUI().getMainWindow(), "This file exists already, do you want to resume an exisiting download?", "Resume Download?", JOptionPane.YES_NO_OPTION);
  142. resume = (result == JOptionPane.YES_OPTION);
  143. }
  144. }
  145. }
  146. if (reverse && !token.isEmpty()) {
  147. new DCCSendWindow(DCCPlugin.this, send, "*Receive: " + nickname, nickname, null);
  148. send.setToken(token);
  149. if (resume) {
  150. if (IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "receive.reverse.sendtoken")) {
  151. parser.sendCTCP(nickname, "DCC", "RESUME " + sendFilename + " 0 " + jc.getSelectedFile().length() + " " + token);
  152. } else {
  153. parser.sendCTCP(nickname, "DCC", "RESUME " + sendFilename + " 0 " + jc.getSelectedFile().length());
  154. }
  155. } else {
  156. if (listen(send)) {
  157. parser.sendCTCP(nickname, "DCC", "SEND " + sendFilename + " " + DCC.ipToLong(getListenIP(parser)) + " " + send.getPort() + " " + send.getFileSize() + " " + token);
  158. } else {
  159. // Listen failed.
  160. }
  161. }
  162. } else {
  163. new DCCSendWindow(DCCPlugin.this, send, "Receive: " + nickname, nickname, null);
  164. if (resume) {
  165. parser.sendCTCP(nickname, "DCC", "RESUME " + sendFilename + " " + send.getPort() + " " + jc.getSelectedFile().length());
  166. } else {
  167. send.connect();
  168. }
  169. }
  170. }
  171. }
  172. }, "saveFileThread: " + sendFilename);
  173. // Start the thread
  174. dccThread.start();
  175. }
  176. /**
  177. * Process an event of the specified type.
  178. *
  179. * @param type The type of the event to process
  180. * @param format Format of messages that are about to be sent. (May be null)
  181. * @param arguments The arguments for the event
  182. */
  183. @Override
  184. public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
  185. handleProcessEvent(type, format, false, arguments);
  186. }
  187. /**
  188. * Make the given DCC start listening.
  189. * This will either call dcc.listen() or dcc.listen(startPort, endPort)
  190. * depending on config.
  191. *
  192. * @param dcc DCC to start listening.
  193. * @return True if Socket was opened.
  194. */
  195. protected boolean listen(final DCC dcc) {
  196. final boolean usePortRange = IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "firewall.ports.usePortRange");
  197. final int startPort = IdentityManager.getGlobalConfig().getOptionInt(getDomain(), "firewall.ports.startPort");
  198. final int endPort = IdentityManager.getGlobalConfig().getOptionInt(getDomain(), "firewall.ports.endPort");
  199. try {
  200. if (usePortRange) {
  201. dcc.listen(startPort, endPort);
  202. } else {
  203. dcc.listen();
  204. }
  205. return true;
  206. } catch (IOException ioe) {
  207. return false;
  208. }
  209. }
  210. /**
  211. * Process an event of the specified type.
  212. *
  213. * @param type The type of the event to process
  214. * @param format Format of messages that are about to be sent. (May be null)
  215. * @param dontAsk Don't ask any questions, assume yes.
  216. * @param arguments The arguments for the event
  217. */
  218. public void handleProcessEvent(final ActionType type, final StringBuffer format, final boolean dontAsk, final Object... arguments) {
  219. if (IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "receive.autoaccept") && !dontAsk) {
  220. handleProcessEvent(type, format, true, arguments);
  221. return;
  222. }
  223. if (type == CoreActionType.SERVER_CTCP) {
  224. final String ctcpType = (String) arguments[2];
  225. final String[] ctcpData = ((String) arguments[3]).split(" ");
  226. if (ctcpType.equalsIgnoreCase("DCC")) {
  227. if (ctcpData[0].equalsIgnoreCase("chat") && ctcpData.length > 3) {
  228. final String nickname = ((ClientInfo) arguments[1]).getNickname();
  229. if (dontAsk) {
  230. final DCCChat chat = new DCCChat();
  231. try {
  232. chat.setAddress(Long.parseLong(ctcpData[2]), Integer.parseInt(ctcpData[3]));
  233. } catch (NumberFormatException nfe) {
  234. return;
  235. }
  236. final String myNickname = ((Server) arguments[0]).getParser().getLocalClient().getNickname();
  237. final DCCFrame f = new DCCChatWindow(this, chat, "Chat: " + nickname, myNickname, nickname);
  238. f.getFrame().addLine("DCCChatStarting", nickname, chat.getHost(), chat.getPort());
  239. chat.connect();
  240. } else {
  241. ActionManager.processEvent(DCCActions.DCC_CHAT_REQUEST, null, ((Server) arguments[0]), nickname);
  242. askQuestion("User " + nickname + " on " + ((Server) arguments[0]).toString() + " would like to start a DCC Chat with you.\n\nDo you want to continue?", "DCC Chat Request", JOptionPane.YES_OPTION, type, format, arguments);
  243. return;
  244. }
  245. } else if (ctcpData[0].equalsIgnoreCase("send") && ctcpData.length > 3) {
  246. final String nickname = ((ClientInfo) arguments[1]).getNickname();
  247. final String filename;
  248. String tmpFilename;
  249. // Clients tend to put files with spaces in the name in "" so lets look for that.
  250. final StringBuilder filenameBits = new StringBuilder();
  251. int i;
  252. final boolean quoted = ctcpData[1].startsWith("\"");
  253. if (quoted) {
  254. for (i = 1; i < ctcpData.length; i++) {
  255. String bit = ctcpData[i];
  256. if (i == 1) {
  257. bit = bit.substring(1);
  258. }
  259. if (bit.endsWith("\"")) {
  260. filenameBits.append(" " + bit.substring(0, bit.length() - 1));
  261. break;
  262. } else {
  263. filenameBits.append(" " + bit);
  264. }
  265. }
  266. tmpFilename = filenameBits.toString().trim();
  267. } else {
  268. tmpFilename = ctcpData[1];
  269. i = 1;
  270. }
  271. // Try to remove path names if sent.
  272. // Change file separatorChar from other OSs first
  273. if (File.separatorChar == '/') {
  274. tmpFilename = tmpFilename.replace('\\', File.separatorChar);
  275. } else {
  276. tmpFilename = tmpFilename.replace('/', File.separatorChar);
  277. }
  278. // Then get just the name of the file.
  279. filename = (new File(tmpFilename)).getName();
  280. final String ip = ctcpData[++i];
  281. final String port = ctcpData[++i];
  282. long size;
  283. if (ctcpData.length + 1 > i) {
  284. try {
  285. size = Integer.parseInt(ctcpData[++i]);
  286. } catch (NumberFormatException nfe) {
  287. size = -1;
  288. }
  289. } else {
  290. size = -1;
  291. }
  292. final String token = (ctcpData.length - 1 > i && !ctcpData[i + 1].equals("T")) ? ctcpData[++i] : "";
  293. // Ignore incorrect ports, or non-numeric IP/Port
  294. try {
  295. int portInt = Integer.parseInt(port);
  296. if (portInt > 65535 || portInt < 0) {
  297. return;
  298. }
  299. Long.parseLong(ip);
  300. } catch (NumberFormatException nfe) {
  301. return;
  302. }
  303. DCCSend send = DCCSend.findByToken(token);
  304. if (send == null && !dontAsk) {
  305. if (!token.isEmpty() && !port.equals("0")) {
  306. // This is a reverse DCC Send that we no longer care about.
  307. return;
  308. } else {
  309. ActionManager.processEvent(DCCActions.DCC_SEND_REQUEST, null, ((Server) arguments[0]), nickname, filename);
  310. askQuestion("User " + nickname + " on " + ((Server) arguments[0]).toString() + " would like to send you a file over DCC.\n\nFile: " + filename + "\n\nDo you want to continue?", "DCC Send Request", JOptionPane.YES_OPTION, type, format, arguments);
  311. return;
  312. }
  313. } else {
  314. final boolean newSend = send == null;
  315. if (newSend) {
  316. send = new DCCSend(IdentityManager.getGlobalConfig().getOptionInt(getDomain(), "send.blocksize"));
  317. send.setTurbo(IdentityManager.getGlobalConfig().getOptionBool(getDomain(), "send.forceturbo"));
  318. }
  319. try {
  320. send.setAddress(Long.parseLong(ip), Integer.parseInt(port));
  321. } catch (NumberFormatException nfe) {
  322. return;
  323. }
  324. if (newSend) {
  325. send.setFileName(filename);
  326. send.setFileSize(size);
  327. saveFile(nickname, send, ((Server) arguments[0]).getParser(), "0".equals(port), (quoted) ? "\"" + filename + "\"" : filename, token);
  328. } else {
  329. send.connect();
  330. }
  331. }
  332. } else if ((ctcpData[0].equalsIgnoreCase("resume") || ctcpData[0].equalsIgnoreCase("accept")) && ctcpData.length > 2) {
  333. final String filename;
  334. // Clients tend to put files with spaces in the name in "" so lets look for that.
  335. final StringBuilder filenameBits = new StringBuilder();
  336. int i;
  337. final boolean quoted = ctcpData[1].startsWith("\"");
  338. if (quoted) {
  339. for (i = 1; i < ctcpData.length; i++) {
  340. String bit = ctcpData[i];
  341. if (i == 1) {
  342. bit = bit.substring(1);
  343. }
  344. if (bit.endsWith("\"")) {
  345. filenameBits.append(" " + bit.substring(0, bit.length() - 1));
  346. break;
  347. } else {
  348. filenameBits.append(" " + bit);
  349. }
  350. }
  351. filename = filenameBits.toString().trim();
  352. } else {
  353. filename = ctcpData[1];
  354. i = 1;
  355. }
  356. try {
  357. final int port = Integer.parseInt(ctcpData[++i]);
  358. final int position = Integer.parseInt(ctcpData[++i]);
  359. final String token = (ctcpData.length - 1 > i) ? " " + ctcpData[++i] : "";
  360. // Now look for a dcc that matches.
  361. for (DCCSend send : DCCSend.getSends()) {
  362. if (send.port == port && (new File(send.getFileName())).getName().equalsIgnoreCase(filename)) {
  363. if ((!token.isEmpty() && !send.getToken().isEmpty()) && (!token.equals(send.getToken()))) {
  364. continue;
  365. }
  366. final Parser parser = ((Server) arguments[0]).getParser();
  367. final String nickname = ((ClientInfo) arguments[1]).getNickname();
  368. if (ctcpData[0].equalsIgnoreCase("resume")) {
  369. parser.sendCTCP(nickname, "DCC", "ACCEPT " + ((quoted) ? "\"" + filename + "\"" : filename) + " " + port + " " + send.setFileStart(position) + token);
  370. } else {
  371. send.setFileStart(position);
  372. if (port == 0) {
  373. // Reverse dcc
  374. if (listen(send)) {
  375. if (send.getToken().isEmpty()) {
  376. parser.sendCTCP(nickname, "DCC", "SEND " + ((quoted) ? "\"" + filename + "\"" : filename) + " " + DCC.ipToLong(send.getHost()) + " " + send.getPort() + " " + send.getFileSize());
  377. } else {
  378. parser.sendCTCP(nickname, "DCC", "SEND " + ((quoted) ? "\"" + filename + "\"" : filename) + " " + DCC.ipToLong(send.getHost()) + " " + send.getPort() + " " + send.getFileSize() + " " + send.getToken());
  379. }
  380. } else {
  381. // Listen failed.
  382. }
  383. } else {
  384. send.connect();
  385. }
  386. }
  387. }
  388. }
  389. } catch (NumberFormatException nfe) {
  390. }
  391. }
  392. }
  393. }
  394. }
  395. /**
  396. * Create the container window.
  397. */
  398. protected void createContainer() {
  399. container = new DCCFrame(this, "DCCs", "dcc") {
  400. };
  401. final TextLabel label = new TextLabel("This is a placeholder window to group DCCs together.");
  402. label.setText(label.getText() + "\n\nClosing this window will close all the active DCCs");
  403. ((TextFrame) container.getFrame()).getContentPane().add(label);
  404. WindowManager.addWindow(container.getFrame());
  405. container.getFrame().open();
  406. }
  407. /**
  408. * Add a window to the container window.
  409. *
  410. * @param window Window to remove
  411. */
  412. protected synchronized void addWindow(final DCCFrame window) {
  413. if (window == container) {
  414. return;
  415. }
  416. if (container == null) {
  417. createContainer();
  418. }
  419. WindowManager.addWindow(container.getFrame(), window.getFrame());
  420. childFrames.add(window);
  421. window.getFrame().open();
  422. }
  423. /**
  424. * Remove a window from the container window.
  425. *
  426. * @param window Window to remove
  427. */
  428. protected synchronized void delWindow(final DCCFrame window) {
  429. if (container == null) {
  430. return;
  431. }
  432. if (window == container) {
  433. container = null;
  434. for (DCCFrame win : childFrames) {
  435. if (win != window) {
  436. win.close();
  437. }
  438. }
  439. childFrames.clear();
  440. } else {
  441. childFrames.remove(window);
  442. if (childFrames.isEmpty()) {
  443. container.close();
  444. container = null;
  445. }
  446. }
  447. }
  448. /** {@inheritDoc} */
  449. @Override
  450. public void domainUpdated() {
  451. final Identity defaults = IdentityManager.getAddonIdentity();
  452. defaults.setOption(getDomain(), "receive.savelocation",
  453. Main.getConfigDir() + "downloads" + System.getProperty("file.separator"));
  454. }
  455. /**
  456. * Called when the plugin is loaded.
  457. */
  458. @Override
  459. public void onLoad() {
  460. final File dir = new File(IdentityManager.getGlobalConfig().getOption(getDomain(), "receive.savelocation"));
  461. if (dir.exists()) {
  462. if (!dir.isDirectory()) {
  463. Logger.userError(ErrorLevel.LOW, "Unable to create download dir (file exists instead)");
  464. }
  465. } else {
  466. try {
  467. dir.mkdirs();
  468. dir.createNewFile();
  469. } catch (IOException ex) {
  470. Logger.userError(ErrorLevel.LOW, "Unable to create download dir");
  471. }
  472. }
  473. command = new DCCCommand(this);
  474. ActionManager.registerActionTypes(DCCActions.values());
  475. ActionManager.addListener(this, CoreActionType.SERVER_CTCP);
  476. }
  477. /**
  478. * Called when this plugin is Unloaded.
  479. */
  480. @Override
  481. public synchronized void onUnload() {
  482. CommandManager.unregisterCommand(command);
  483. ActionManager.removeListener(this);
  484. if (container != null) {
  485. container.close();
  486. }
  487. }
  488. /**
  489. * Get the IP Address we should send as our listening IP.
  490. *
  491. * @return The IP Address we should send as our listening IP.
  492. */
  493. public String getListenIP() {
  494. return getListenIP(null);
  495. }
  496. /**
  497. * Get the IP Address we should send as our listening IP.
  498. *
  499. * @param parser Parser the IRC Parser where this dcc is initiated
  500. * @return The IP Address we should send as our listening IP.
  501. */
  502. public String getListenIP(final Parser parser) {
  503. final String configIP = IdentityManager.getGlobalConfig().getOption(getDomain(), "firewall.ip");
  504. if (!configIP.isEmpty()) {
  505. return configIP;
  506. } else if (parser != null) {
  507. final String myHost = parser.getLocalClient().getHostname();
  508. if (!myHost.isEmpty()) {
  509. try {
  510. return InetAddress.getByName(myHost).getHostAddress();
  511. } catch (UnknownHostException e) { /* Will return default host below */ }
  512. }
  513. }
  514. try {
  515. return InetAddress.getLocalHost().getHostAddress();
  516. } catch (UnknownHostException e) {
  517. // This is almost certainly not what we want, but we can't work out
  518. // the right one.
  519. return "127.0.0.1";
  520. }
  521. }
  522. /** {@inheritDoc} */
  523. @Override
  524. public void showConfig(final PreferencesManager manager) {
  525. final PreferencesCategory general = new PreferencesCategory("DCC", "", "category-dcc");
  526. final PreferencesCategory firewall = new PreferencesCategory("Firewall", "");
  527. final PreferencesCategory sending = new PreferencesCategory("Sending", "");
  528. final PreferencesCategory receiving = new PreferencesCategory("Receiving", "");
  529. manager.getCategory("Plugins").addSubCategory(general.setInlineAfter());
  530. general.addSubCategory(firewall.setInline());
  531. general.addSubCategory(sending.setInline());
  532. general.addSubCategory(receiving.setInline());
  533. firewall.addSetting(new PreferencesSetting(PreferencesType.TEXT,
  534. getDomain(), "firewall.ip", "Forced IP",
  535. "What IP should be sent as our IP (Blank = work it out)"));
  536. firewall.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  537. getDomain(), "firewall.ports.usePortRange", "Use Port Range",
  538. "Useful if you have a firewall that only forwards specific ports"));
  539. firewall.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
  540. getDomain(), "firewall.ports.startPort", "Start Port",
  541. "Port to try to listen on first"));
  542. firewall.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
  543. getDomain(), "firewall.ports.endPort", "End Port",
  544. "Port to try to listen on last"));
  545. receiving.addSetting(new PreferencesSetting(PreferencesType.TEXT,
  546. getDomain(), "receive.savelocation", "Default save location",
  547. "Where the save as window defaults to?"));
  548. sending.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  549. getDomain(), "send.reverse", "Reverse DCC",
  550. "With reverse DCC, the sender connects rather than " +
  551. "listens like normal dcc"));
  552. sending.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  553. getDomain(), "send.forceturbo", "Use Turbo DCC",
  554. "Turbo DCC doesn't wait for ack packets. this is " +
  555. "faster but not always supported."));
  556. receiving.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  557. getDomain(), "receive.reverse.sendtoken",
  558. "Send token in reverse receive",
  559. "If you have problems with reverse dcc receive resume," +
  560. " try toggling this."));
  561. general.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
  562. getDomain(), "send.blocksize", "Blocksize to use for DCC",
  563. "Change the block size for send/receive, this can " +
  564. "sometimes speed up transfers."));
  565. }
  566. }