├── .idea
├── .gitignore
├── artifacts
│ └── LiteFTPD_UNIX_jar.xml
├── misc.xml
├── modules.xml
├── uiDesigner.xml
└── vcs.xml
├── How-to-LiteFTPD-UNIX.gif
├── LICENSE
├── LiteFTPD-UNIX.iml
├── README-EN.md
├── README.md
├── config.prop
├── release
└── LiteFTPD-UNIX.jar
└── src
├── META-INF
└── MANIFEST.MF
└── pers
└── adlered
└── liteftpd
├── analyze
├── CommandAnalyze.java
└── PrivateVariable.java
├── dict
├── Dict.java
└── StatusCode.java
├── graphic
├── main
│ ├── GraphicMain.java
│ └── model
│ │ └── MainModels.java
└── update
│ └── RunningUpdate.java
├── logger
├── Filter.java
├── Logger.java
└── enums
│ ├── Levels.java
│ └── Types.java
├── main
└── Main.java
├── mode
├── PASV.java
└── PORT.java
├── pool
└── handler
│ └── HandlerPool.java
├── tool
├── AutoInputStream.java
├── CharsetSelector.java
├── ConsoleTable.java
├── GoodXX.java
├── LocalAddress.java
├── RandomNum.java
└── Status.java
├── user
├── User.java
├── UserProps.java
├── info
│ ├── OnlineInfo.java
│ └── bind
│ │ └── UserInfoBind.java
├── status
│ ├── Online.java
│ └── bind
│ │ ├── IPAddressBind.java
│ │ ├── IpLimitBind.java
│ │ ├── SpeedLimitBind.java
│ │ └── UserLimitBind.java
└── verify
│ └── OnlineRules.java
├── variable
├── OnlineUserController.java
└── Variable.java
└── wizard
├── config
└── Prop.java
└── init
├── PauseListen.java
├── Receive.java
├── Send.java
└── SocketHandler.java
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/.idea/artifacts/LiteFTPD_UNIX_jar.xml:
--------------------------------------------------------------------------------
1 |
To analyze user input into command, and execute it.
36 | * 37 | * @author : https://github.com/AdlerED 38 | * @date : 2019-09-19 09:21 39 | **/ 40 | public class CommandAnalyze { 41 | /** 42 | * Step 1: Required username; 43 | * Step 2: Required password; 44 | * Step 3: Logged in. 45 | */ 46 | private int step = 1; 47 | 48 | private String loginUser = null; 49 | private String loginPass = null; 50 | private String SRVIPADD = null; 51 | 52 | private Send send = null; 53 | 54 | private File file = null; 55 | private PASV passiveMode = null; 56 | private PORT portMode = null; 57 | private String mode = null; 58 | 59 | private String currentPath = null; 60 | private String lockPath = null; 61 | private String RNFR = null; 62 | //Trans type default A 63 | //A: ASCII I: BINARY 64 | private String type = "A"; 65 | //To change timeout when command input 66 | private PauseListen pauseListen = null; 67 | private IPAddressBind ipAddressBind = null; 68 | 69 | private PrivateVariable privateVariable = null; 70 | private UserProps userProps = null; 71 | 72 | private IpLimitBind ipLimitBind = null; 73 | private UserLimitBind userLimitBind = null; 74 | 75 | public CommandAnalyze(Send send, String SRVIPADD, PrivateVariable privateVariable, PauseListen pauseListen, IPAddressBind ipAddressBind, IpLimitBind ipLimitBind) { 76 | this.send = send; 77 | this.SRVIPADD = SRVIPADD; 78 | this.privateVariable = privateVariable; 79 | this.pauseListen = pauseListen; 80 | this.ipAddressBind = ipAddressBind; 81 | this.ipLimitBind = ipLimitBind; 82 | } 83 | 84 | public static boolean isPortUsing(String host, int port) { 85 | boolean flag = false; 86 | try { 87 | Socket socket = new Socket(host, port); 88 | flag = true; 89 | socket.close(); 90 | } catch (IOException IOE) { 91 | Logger.log(Types.SYS, Levels.DEBUG, "Port " + port + " already in use, re-generating..."); 92 | } 93 | return flag; 94 | } 95 | 96 | public static void delFolder(String folderPath) { 97 | try { 98 | delAllFile(folderPath); //删除完里面所有内容 99 | String filePath = folderPath; 100 | filePath = filePath; 101 | java.io.File myFilePath = new java.io.File(filePath); 102 | myFilePath.delete(); //删除空文件夹 103 | } catch (Exception e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | public static boolean delAllFile(String path) { 109 | boolean flag = false; 110 | File file = new File(path); 111 | if (!file.exists()) { 112 | return flag; 113 | } 114 | if (!file.isDirectory()) { 115 | return flag; 116 | } 117 | String[] tempList = file.list(); 118 | File temp = null; 119 | for (int i = 0; i < tempList.length; i++) { 120 | if (path.endsWith(File.separator)) { 121 | temp = new File(path + tempList[i]); 122 | } else { 123 | temp = new File(path + File.separator + tempList[i]); 124 | } 125 | if (temp.isFile()) { 126 | temp.delete(); 127 | } 128 | if (temp.isDirectory()) { 129 | delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件 130 | delFolder(path + "/" + tempList[i]);//再删除空文件夹 131 | flag = true; 132 | } 133 | } 134 | return flag; 135 | } 136 | 137 | public void analyze(String command) { 138 | pauseListen.resetTimeout(); 139 | String cmd = null; 140 | String arg1 = null; 141 | String arg2 = null; 142 | String[] split = null; 143 | try { 144 | split = command.split(" "); 145 | for (int i = 0; i < split.length; i++) { 146 | split[i] = split[i].replaceAll("(\r|\n)", ""); 147 | } 148 | cmd = split[0]; 149 | if (split.length == 2) { 150 | arg1 = split[1]; 151 | } else if (split.length > 2) { 152 | arg1 = split[1]; 153 | arg2 = split[2]; 154 | } 155 | } catch (Exception E) { 156 | //TODO 157 | E.printStackTrace(); 158 | } 159 | if (cmd != null) { 160 | cmd = cmd.toUpperCase(); 161 | switch (step) { 162 | case 1: 163 | if (cmd.equals("USER")) { 164 | if (arg1 == null) { 165 | arg1 = "anonymous"; 166 | } 167 | privateVariable.setUsername(arg1); 168 | Logger.log(Types.SYS, Levels.DEBUG, Thread.currentThread() + " User login: " + arg1); 169 | loginUser = arg1; 170 | send.send(Dict.passwordRequired(loginUser)); 171 | step = 2; 172 | } else if (cmd.equals("BYE") || cmd.equals("QUIT")) { 173 | send.send(Dict.bye()); 174 | privateVariable.setInterrupted(true); 175 | } else if (cmd.equals("OPTS")) { 176 | if (arg1 != null) { 177 | arg1 = arg1.toUpperCase(); 178 | if (arg1.equals("UTF8")) { 179 | if (arg2 != null) { 180 | arg2 = arg2.toUpperCase(); 181 | if (arg2.equals("ON")) { 182 | privateVariable.setEncode("UTF-8"); 183 | privateVariable.setEncodeLock(true); 184 | send.send(Dict.utf8(true)); 185 | } else if (arg2.equals("OFF")) { 186 | privateVariable.setEncode(Variable.defaultEncode); 187 | privateVariable.setEncodeLock(true); 188 | send.send(Dict.utf8(false)); 189 | } 190 | } 191 | } 192 | } 193 | } else { 194 | unknownCommand(); 195 | } 196 | break; 197 | case 2: 198 | if (cmd.equals("PASS")) { 199 | Logger.log(Types.SYS, Levels.DEBUG, "User " + loginUser + "'s password: " + arg1); 200 | loginPass = arg1; 201 | userLimitBind = OnlineRules.checkUsername(loginUser); 202 | if (userLimitBind.getUsername() == null) { 203 | send.send(Dict.tooMuchLoginInUser(loginUser)); 204 | privateVariable.reason = "user \"" + loginUser + "\" has too much login"; 205 | privateVariable.setInterrupted(true); 206 | } else { 207 | try { 208 | userProps = User.getUserProps(loginUser); 209 | if ((loginUser.equals("anonymous") && userProps.getPermission() != null) || User.checkPassword(loginUser, loginPass)) { 210 | OnlineInfo.usersOnlineInfo.add(new UserInfoBind(ipLimitBind, userLimitBind)); 211 | send.send(Dict.loggedIn(loginUser)); 212 | Logger.log(Types.SYS, Levels.INFO, "User " + loginUser + " logged in."); 213 | lockPath = userProps.getPermitDir(); 214 | currentPath = userProps.getDefaultDir(); 215 | OnlineUserController.printOnline(); 216 | step = 3; 217 | } else { 218 | send.send(Dict.wrongPassword()); 219 | privateVariable.setInterrupted(true); 220 | } 221 | } catch (NullPointerException NPE) { 222 | send.send(Dict.wrongPassword()); 223 | privateVariable.setInterrupted(true); 224 | } 225 | } 226 | } else if (cmd.equals("BYE") || cmd.equals("QUIT")) { 227 | send.send(Dict.bye()); 228 | privateVariable.setInterrupted(true); 229 | } else { 230 | unknownCommand(); 231 | } 232 | break; 233 | case 3: 234 | if (cmd.equals("USER") || cmd.equals("PASS")) { 235 | send.send(Dict.alreadyLogIn()); 236 | } 237 | /** 238 | * INFO COMMANDS 239 | */ 240 | else if (cmd.equals("FEAT")) { 241 | send.send(Dict.features()); 242 | } else if (cmd.equals("SITE")) { 243 | send.send(Dict.notSupportSITE()); 244 | } 245 | /** 246 | * NORMAL COMMANDS 247 | */ 248 | else if (cmd.equals("PWD")) { 249 | //if (file.isDirectory()) { 250 | send.send(Dict.currentDir(getLockPath(currentPath, lockPath))); 251 | //} else { 252 | // send.send(Dict.isFile + file.getName() + "" + Dict.newLine); 253 | //} 254 | } else if (cmd.equals("TYPE")) { 255 | arg1 = arg1.toUpperCase(); 256 | type = arg1; 257 | send.send(Dict.type(arg1)); 258 | } else if (cmd.equals("BINARY")) { 259 | type = "I"; 260 | send.send(Dict.type("I")); 261 | } else if (cmd.equals("ASCII")) { 262 | type = "A"; 263 | send.send(Dict.type("A")); 264 | } else if (cmd.equals("BYE") || cmd.equals("QUIT") || cmd.equals("EXIT")) { 265 | send.send(Dict.bye()); 266 | privateVariable.setInterrupted(true); 267 | } else if (cmd.equals("LIST")) { 268 | send.send(Dict.list()); 269 | privateVariable.setTimeoutLock(true); 270 | try { 271 | Process process = Runtime.getRuntime().exec(new String[]{"ls", "-l", currentPath}); 272 | process.waitFor(); 273 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 274 | String line; 275 | StringBuilder result = new StringBuilder(); 276 | while ((line = bufferedReader.readLine()) != null) { 277 | result.append(line).append('\n'); 278 | } 279 | if (mode != null) { 280 | Logger.log(Types.TRANS, Levels.DEBUG, "Reset mode."); 281 | String mode = this.mode; 282 | this.mode = null; 283 | Logger.log(Types.TRANS, Levels.DEBUG, "Hello " + mode + " mode."); 284 | switch (mode) { 285 | case "port": 286 | portMode.hello(result.toString()); 287 | portMode.start(); 288 | break; 289 | case "passive": 290 | passiveMode.hello(result.toString()); 291 | break; 292 | } 293 | } 294 | } catch (IOException IOE) { 295 | //TODO 296 | IOE.printStackTrace(); 297 | } catch (InterruptedException IE) { 298 | //TODO 299 | IE.printStackTrace(); 300 | } 301 | } else if (cmd.equals("CDUP")) { 302 | upperDirectory(); 303 | send.send(Dict.changeDir(getLockPath(currentPath, lockPath))); 304 | } else if (cmd.equals("CWD")) { 305 | if (arg1 != null) { 306 | String completePath = arg1; 307 | if (arg2 != null) { 308 | for (int i = 2; i < split.length; i++) { 309 | //Make "/Users/$" to "/Users$" 310 | if (i == split.length - 1) { 311 | split[i] = split[i].replaceAll("/$", ""); 312 | } 313 | //Add 314 | completePath += " " + split[i]; 315 | } 316 | } 317 | if (completePath.equals("..")) { 318 | upperDirectory(); 319 | send.send(Dict.changeDir(getLockPath(currentPath, lockPath))); 320 | } else { 321 | if (completePath.indexOf("../") != -1) { 322 | completePath = completePath.replaceAll("\\.\\./", ""); 323 | } 324 | completePath = getAbsolutePath(completePath); 325 | File file = new File(completePath); 326 | if (file.exists()) { 327 | if (file.isFile()) { 328 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 329 | } else { 330 | currentPath = completePath; 331 | send.send(Dict.changeDir(getLockPath(currentPath, lockPath))); 332 | } 333 | } else { 334 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 335 | } 336 | } 337 | } else { 338 | send.send(Dict.unknownCommand()); 339 | } 340 | } else if (cmd.equals("SYST")) { 341 | send.send(Dict.unixType()); 342 | } else if (cmd.equals("NOOP")) { 343 | privateVariable.setTimeoutLock(true); 344 | send.send(Dict.commandOK()); 345 | } else if (cmd.equals("MKD")) { 346 | if (userProps.getPermission().contains("c")) { 347 | String completePath = arg1; 348 | if (arg2 != null) { 349 | for (int i = 2; i < split.length; i++) { 350 | completePath += " " + split[i]; 351 | } 352 | } 353 | if (completePath.indexOf("../") != -1) { 354 | completePath = completePath.replaceAll("\\.\\./", ""); 355 | } 356 | completePath = getAbsolutePath(completePath); 357 | File file = new File(completePath); 358 | if (!file.exists()) { 359 | file.mkdirs(); 360 | send.send(Dict.dirCreated(getLockPath(completePath, lockPath))); 361 | } else { 362 | send.send(Dict.createFailed(getLockPath(completePath, lockPath))); 363 | } 364 | } else { 365 | send.send(Dict.permissionDenied()); 366 | } 367 | } else if (cmd.equals("RMD")) { 368 | if (userProps.getPermission().contains("d")) { 369 | String completePath = arg1; 370 | if (arg2 != null) { 371 | for (int i = 2; i < split.length; i++) { 372 | completePath += " " + split[i]; 373 | } 374 | } 375 | if (completePath.indexOf("../") != -1) { 376 | completePath = completePath.replaceAll("\\.\\./", ""); 377 | } 378 | completePath = getAbsolutePath(completePath); 379 | File file = new File(completePath); 380 | if (file.isDirectory()) { 381 | delFolder(completePath); 382 | send.send(Dict.rmdSuccess()); 383 | } else if (file.isFile()) { 384 | file.delete(); 385 | send.send(Dict.rmdSuccess()); 386 | } else { 387 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 388 | } 389 | } else { 390 | send.send(Dict.permissionDenied()); 391 | } 392 | } else if (cmd.equals("DELE")) { 393 | if (userProps.getPermission().contains("d")) { 394 | String completePath = arg1; 395 | if (arg2 != null) { 396 | for (int i = 2; i < split.length; i++) { 397 | completePath += " " + split[i]; 398 | } 399 | } 400 | if (completePath.indexOf("../") != -1) { 401 | completePath = completePath.replaceAll("\\.\\./", ""); 402 | } 403 | completePath = getAbsolutePath(completePath); 404 | File file = new File(completePath); 405 | if (file.isFile()) { 406 | file.delete(); 407 | send.send(Dict.deleSuccess()); 408 | } else { 409 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 410 | } 411 | } else { 412 | send.send(Dict.permissionDenied()); 413 | } 414 | } else if (cmd.equals("RNFR")) { 415 | if (userProps.getPermission().contains("m")) { 416 | String completePath = arg1; 417 | if (arg2 != null) { 418 | for (int i = 2; i < split.length; i++) { 419 | completePath += " " + split[i]; 420 | } 421 | } 422 | if (completePath.indexOf("../") != -1) { 423 | completePath = completePath.replaceAll("\\.\\./", ""); 424 | } 425 | completePath = getAbsolutePath(completePath); 426 | File file = new File(completePath); 427 | if (file.exists()) { 428 | RNFR = completePath; 429 | send.send(Dict.rnfrSuccess()); 430 | } else { 431 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 432 | } 433 | } else { 434 | send.send(Dict.permissionDenied()); 435 | } 436 | } else if (cmd.equals("RNTO")) { 437 | if (userProps.getPermission().contains("m")) { 438 | String completePath = arg1; 439 | if (arg2 != null) { 440 | for (int i = 2; i < split.length; i++) { 441 | completePath += " " + split[i]; 442 | } 443 | } 444 | if (completePath.indexOf("../") != -1) { 445 | completePath = completePath.replaceAll("\\.\\./", ""); 446 | } 447 | completePath = getAbsolutePath(completePath); 448 | File file = new File(RNFR); 449 | if (file.renameTo(new File(completePath))) { 450 | send.send(Dict.rntoSuccess()); 451 | } else { 452 | send.send(Dict.notFound(getLockPath(completePath, lockPath))); 453 | } 454 | RNFR = null; 455 | } else { 456 | send.send(Dict.permissionDenied()); 457 | } 458 | } 459 | /** 460 | * TRANSMISSION COMMANDS 461 | */ 462 | else if (cmd.equals("PORT")) { 463 | String completePath = arg1; 464 | if (arg2 != null) { 465 | for (int i = 2; i < split.length; i++) { 466 | completePath += " " + split[i]; 467 | } 468 | } 469 | String[] analyzeStep1 = completePath.split(","); 470 | int[] analyzeStep2 = new int[analyzeStep1.length]; 471 | for (int i = 0; i < analyzeStep1.length; i++) { 472 | analyzeStep2[i] = Integer.parseInt(analyzeStep1[i]); 473 | } 474 | String ip = ""; 475 | int port = -1; 476 | try { 477 | for (int i = 0; i < 4; i++) { 478 | if (i < 3) { 479 | ip += analyzeStep2[i] + "."; 480 | } else { 481 | ip += analyzeStep2[i]; 482 | } 483 | } 484 | port = (analyzeStep2[4] * 256) + analyzeStep2[5]; 485 | } catch (ArrayIndexOutOfBoundsException AIOOBE) { 486 | AIOOBE.printStackTrace(); 487 | } 488 | if (portMode != null) { 489 | portMode.stopSocket(); 490 | } 491 | portMode = new PORT(send, privateVariable, pauseListen, type, OnlineRules.getSpeedLimit(loginUser)); 492 | portMode.setTarget(ip, port); 493 | send.send(Dict.portSuccess()); 494 | mode = "port"; 495 | } else if (cmd.equals("PASV")) { 496 | if (passiveMode != null) { 497 | passiveMode.stopSocket(); 498 | } 499 | passiveMode = new PASV(send, privateVariable, pauseListen, type, OnlineRules.getSpeedLimit(loginUser)); 500 | int randomPort; 501 | int randomSub; 502 | int calcPort; 503 | int finalPort; 504 | do { 505 | MapStore values when service is running to make sure every model works together.
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-09-19 09:21 9 | **/ 10 | public class PrivateVariable { 11 | public boolean interrupted = false; 12 | public String encode = "UTF-8"; 13 | public String reason = null; 14 | private String username = null; 15 | //When translating, turn the timeout on to avoid timeout & disconnect. 16 | private boolean timeoutLock = false; 17 | //If Encode Lock is on, smart encode will not working. 18 | private boolean encodeLock = false; 19 | //Rest 20 | private long rest = 0l; 21 | 22 | public String getUsername() { 23 | return username; 24 | } 25 | 26 | public void setUsername(String username) { 27 | this.username = username; 28 | } 29 | 30 | public boolean isEncodeLock() { 31 | return encodeLock; 32 | } 33 | 34 | public void setEncodeLock(boolean encodeLock) { 35 | this.encodeLock = encodeLock; 36 | } 37 | 38 | public boolean isTimeoutLock() { 39 | return timeoutLock; 40 | } 41 | 42 | public void setTimeoutLock(boolean timeoutLock) { 43 | this.timeoutLock = timeoutLock; 44 | } 45 | 46 | public boolean isInterrupted() { 47 | return interrupted; 48 | } 49 | 50 | public void setInterrupted(boolean interrupted) { 51 | this.interrupted = interrupted; 52 | } 53 | 54 | public String getEncode() { 55 | return encode; 56 | } 57 | 58 | public void setEncode(String encode) { 59 | this.encode = encode; 60 | } 61 | 62 | public long getRest() { 63 | return rest; 64 | } 65 | 66 | public void setRest(long rest) { 67 | this.rest = rest; 68 | } 69 | 70 | public void resetRest() { 71 | rest = 0l; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/dict/Dict.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.dict; 2 | 3 | import pers.adlered.liteftpd.tool.GoodXX; 4 | import pers.adlered.liteftpd.variable.Variable; 5 | 6 | /** 7 | *Store status messages with response format.
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-09-19 09:21 12 | **/ 13 | public class Dict { 14 | private static String lang = "en_us"; 15 | 16 | public static void init(String lang) { 17 | lang = lang.toLowerCase(); 18 | Dict.lang = lang; 19 | } 20 | 21 | public static String gbEncodeOK(String ip) { 22 | if (lang.equals("zh_cn")) 23 | return StatusCode.SERVICEREADY + "-LiteFTPD" + Dict.newLine 24 | + ">>> 编码已适应Windows FTP客户端,您现在看到的这条信息应是正常的简体中文。" 25 | + Dict.newLine + ">>> 你的IP地址: " + ip 26 | + "" + Dict.newLine + "220" + " :) " + Variable.welcomeMessage + "" + Dict.newLine; 27 | if (lang.equals("en_us")) 28 | return StatusCode.SERVICEREADY + "-LiteFTPD" + Dict.newLine 29 | + ">>> 编码已适应Windows FTP客户端,您现在看到的这条信息应是正常的简体中文。" 30 | + Dict.newLine + ">>> Your IP address: " + ip 31 | + "" + Dict.newLine + "220" + " :) " + Variable.welcomeMessage + "" + Dict.newLine; 32 | return null; 33 | } 34 | 35 | public static String rest(String restAt) { 36 | if (lang.equals("zh_cn")) 37 | return StatusCode.WAIT + " 断点续传已设定于 " + restAt + ". 发送 STORE 或 RETRIEVE 以继续." + Dict.newLine; 38 | if (lang.equals("en_us")) 39 | return StatusCode.WAIT + " Restarting at " + restAt + ". Send STORE or RETRIEVE." + Dict.newLine; 40 | return null; 41 | } 42 | 43 | public static String noSuchFile(String path) { 44 | if (lang.equals("zh_cn")) 45 | return StatusCode.ERRTARGET + " " + path + ": 没有这个文件." + Dict.newLine; 46 | if (lang.equals("en_us")) 47 | return StatusCode.ERRTARGET + " " + path + ": No such file." + Dict.newLine; 48 | return null; 49 | } 50 | 51 | public static String fileSize(long size) { 52 | if (lang.equals("zh_cn")) 53 | return StatusCode.FILESTATUS + " " + size + Dict.newLine; 54 | if (lang.equals("en_us")) 55 | return StatusCode.FILESTATUS + " " + size + Dict.newLine; 56 | return null; 57 | } 58 | 59 | public static String openAscii(String path) { 60 | if (lang.equals("zh_cn")) 61 | return StatusCode.STATUSOK + " 为 " + path + " 开启 ASCII 模式传输数据." + Dict.newLine; 62 | if (lang.equals("en_us")) 63 | return StatusCode.STATUSOK + " Opening ASCII mode data connection for " + path + "." + Dict.newLine; 64 | return null; 65 | } 66 | 67 | public static String openBin(String path) { 68 | if (lang.equals("zh_cn")) 69 | return StatusCode.STATUSOK + " 为 " + path + " 开启 BINARY 模式传输数据." + Dict.newLine; 70 | if (lang.equals("en_us")) 71 | return StatusCode.STATUSOK + " Opening BINARY mode data connection for " + path + "." + Dict.newLine; 72 | return null; 73 | } 74 | 75 | public static String pasvDataFailed() { 76 | if (lang.equals("zh_cn")) 77 | return StatusCode.UNAVAILABLE + " 被动模式接口无连接." + Dict.newLine; 78 | if (lang.equals("en_us")) 79 | return StatusCode.UNAVAILABLE + " Passive port is not connected." + Dict.newLine; 80 | return null; 81 | } 82 | 83 | public static String openPasvAscii(String path, long fileLength) { 84 | if (lang.equals("zh_cn")) 85 | return StatusCode.STATUSOK + " 启动 ASCII 模式数据传输: " + path + " (" + fileLength + " 字节)" + Dict.newLine; 86 | if (lang.equals("en_us")) 87 | return StatusCode.STATUSOK + " Opening ASCII mode data connection for " + path + " (" + fileLength + " Bytes)" + Dict.newLine; 88 | return null; 89 | } 90 | 91 | public static String openPasvBin(String path, long fileLength) { 92 | if (lang.equals("zh_cn")) 93 | return StatusCode.STATUSOK + " 启动 BINARY 模式数据传输: " + path + " (" + fileLength + " 字节)" + Dict.newLine; 94 | if (lang.equals("en_us")) 95 | return StatusCode.STATUSOK + " Opening BINARY mode data connection for " + path + " (" + fileLength + " Bytes)" + Dict.newLine; 96 | return null; 97 | } 98 | 99 | public static String pasvMode(String[] IPADD, int calcPort, int randomSub) { 100 | if (lang.equals("zh_cn")) 101 | return StatusCode.PASSIVE + " Entering Passive Mode " + "(" + IPADD[0] + "," + IPADD[1] + "," + IPADD[2] + "," + IPADD[3] + "," + calcPort + "," + randomSub + ")" + "" + Dict.newLine; 102 | if (lang.equals("en_us")) 103 | return StatusCode.PASSIVE + " Entering Passive Mode " + "(" + IPADD[0] + "," + IPADD[1] + "," + IPADD[2] + "," + IPADD[3] + "," + calcPort + "," + randomSub + ")" + "" + Dict.newLine; 104 | return null; 105 | } 106 | 107 | public static String portSuccess() { 108 | if (lang.equals("zh_cn")) 109 | return StatusCode.SUCCESS + " PORT 命令已执行." + Dict.newLine; 110 | if (lang.equals("en_us")) 111 | return StatusCode.SUCCESS + " PORT Command successful." + Dict.newLine; 112 | return null; 113 | } 114 | 115 | public static String rntoSuccess() { 116 | if (lang.equals("zh_cn")) 117 | return StatusCode.CORRECT + " RNTO 命令已执行." + Dict.newLine; 118 | if (lang.equals("en_us")) 119 | return StatusCode.CORRECT + " RNTO command successful." + Dict.newLine; 120 | return null; 121 | } 122 | 123 | public static String rnfrSuccess() { 124 | if (lang.equals("zh_cn")) 125 | return StatusCode.WAIT + " 文件或文件夹已选定, 请提供目标位置." + Dict.newLine; 126 | if (lang.equals("en_us")) 127 | return StatusCode.WAIT + " File or directory exists, ready for destination name." + Dict.newLine; 128 | return null; 129 | } 130 | 131 | public static String deleSuccess() { 132 | if (lang.equals("zh_cn")) 133 | return StatusCode.CORRECT + " DELE 命令已执行." + Dict.newLine; 134 | if (lang.equals("en_us")) 135 | return StatusCode.CORRECT + " DELE command successful." + Dict.newLine; 136 | return null; 137 | } 138 | 139 | public static String rmdSuccess() { 140 | if (lang.equals("zh_cn")) 141 | return StatusCode.CORRECT + " RMD 命令已执行." + Dict.newLine; 142 | if (lang.equals("en_us")) 143 | return StatusCode.CORRECT + " RMD command successful." + Dict.newLine; 144 | return null; 145 | } 146 | 147 | public static String createFailed(String path) { 148 | if (lang.equals("zh_cn")) 149 | return StatusCode.ERRTARGET + " " + path + ": 创建失败." + Dict.newLine; 150 | if (lang.equals("en_us")) 151 | return StatusCode.ERRTARGET + " " + path + ": Failed to create." + Dict.newLine; 152 | return null; 153 | } 154 | 155 | public static String dirCreated(String path) { 156 | if (lang.equals("zh_cn")) 157 | return StatusCode.CPATH + " 目录 \"" + path + "\" 已创建." + Dict.newLine; 158 | if (lang.equals("en_us")) 159 | return StatusCode.CPATH + " \"" + path + "\" directory created." + Dict.newLine; 160 | return null; 161 | } 162 | 163 | public static String commandOK() { 164 | if (lang.equals("zh_cn")) 165 | return StatusCode.SUCCESS + " 命令已执行." + Dict.newLine; 166 | if (lang.equals("en_us")) 167 | return StatusCode.SUCCESS + " Command okay." + Dict.newLine; 168 | return null; 169 | } 170 | 171 | public static String unixType() { 172 | if (lang.equals("zh_cn")) 173 | return StatusCode.NAME + " UNIX Type: L8" + Dict.newLine; 174 | if (lang.equals("en_us")) 175 | return StatusCode.NAME + " UNIX Type: L8" + Dict.newLine; 176 | return null; 177 | } 178 | 179 | public static String unknownCommand() { 180 | if (lang.equals("zh_cn")) 181 | return StatusCode.CMDUNKNOWN + " 未知命令." + Dict.newLine; 182 | if (lang.equals("en_us")) 183 | return StatusCode.CMDUNKNOWN + " Command don't understood." + Dict.newLine; 184 | return null; 185 | } 186 | 187 | public static String notFound(String path) { 188 | if (lang.equals("zh_cn")) 189 | return StatusCode.ERRTARGET + " " + path + ": 文件或文件夹不存在." + Dict.newLine; 190 | if (lang.equals("en_us")) 191 | return StatusCode.ERRTARGET + " " + path + ": No such file or directory." + Dict.newLine; 192 | return null; 193 | } 194 | 195 | public static String changeDir(String path) { 196 | if (lang.equals("zh_cn")) 197 | return StatusCode.CORRECT + " 目录已更改至 " + path + Dict.newLine; 198 | if (lang.equals("en_us")) 199 | return StatusCode.CORRECT + " Directory changed to " + path + Dict.newLine; 200 | return null; 201 | } 202 | 203 | public static String list() { 204 | if (lang.equals("zh_cn")) 205 | return StatusCode.STATUSOK + " 正在传输 ASCII 数据, 请稍候." + Dict.newLine; 206 | if (lang.equals("en_us")) 207 | return StatusCode.STATUSOK + " Opening ASCII mode data, please wait." + Dict.newLine; 208 | return null; 209 | } 210 | 211 | public static String type(String type) { 212 | if (lang.equals("zh_cn")) 213 | return StatusCode.SUCCESS + " 传输模式已设定为 " + type + "." + Dict.newLine; 214 | if (lang.equals("en_us")) 215 | return StatusCode.SUCCESS + " Type set to " + type + "." + Dict.newLine; 216 | return null; 217 | } 218 | 219 | public static String currentDir(String path) { 220 | if (lang.equals("zh_cn")) 221 | return StatusCode.CPATH + " \"" + path + "\" 是当前的目录." + "" + Dict.newLine; 222 | if (lang.equals("en_us")) 223 | return StatusCode.CPATH + " \"" + path + "\" is current directory." + "" + Dict.newLine; 224 | return null; 225 | } 226 | 227 | public static String notSupportSITE() { 228 | if (lang.equals("zh_cn")) 229 | return StatusCode.ERRSYNTAX + " SITE 选项不受支持." + Dict.newLine; 230 | if (lang.equals("en_us")) 231 | return StatusCode.ERRSYNTAX + " SITE option not supported." + Dict.newLine; 232 | return null; 233 | } 234 | 235 | public static String features() { 236 | if (lang.equals("zh_cn")) 237 | return StatusCode.STATUS + "-特性:" + Dict.newLine 238 | + "UTF8" + Dict.newLine 239 | + StatusCode.STATUS + " 结束" + Dict.newLine; if (lang.equals("en_us")) 240 | return StatusCode.STATUS + "-Features:" + Dict.newLine 241 | + "UTF8" + Dict.newLine 242 | + StatusCode.STATUS + " End" + Dict.newLine; 243 | return null; 244 | } 245 | 246 | public static String alreadyLogIn() { 247 | if (lang.equals("zh_cn")) 248 | return StatusCode.CMDUNKNOWN + " 你已经登录过了." + "" + Dict.newLine; 249 | if (lang.equals("en_us")) 250 | return StatusCode.CMDUNKNOWN + " You have already logged in." + "" + Dict.newLine; 251 | return null; 252 | } 253 | 254 | public static String wrongPassword() { 255 | if (lang.equals("zh_cn")) 256 | return StatusCode.NOTLOGIN + " 抱歉, 密码错误." + Dict.newLine; 257 | if (lang.equals("en_us")) 258 | return StatusCode.NOTLOGIN + " Sorry, the password is wrong." + Dict.newLine; 259 | return null; 260 | } 261 | 262 | public static String loggedIn(String username) { 263 | if (lang.equals("zh_cn")) 264 | return StatusCode.LOGGED + "-" + Dict.newLine + "===------===" + Dict.newLine + ">>> :) Good " + GoodXX.getTimeAsWord() + ", " + username + "!" + Dict.newLine 265 | + ">>> LiteFTPD https://github.com/AdlerED/LiteFTPD-UNIX" + Dict.newLine + "===------===" + Dict.newLine 266 | + "IS THE CHINESE ON THE RIGHT NORMAL? -> 中文 <- If not, type \"quote gb\" to change the encode type." + Dict.newLine + "230 OK" + Dict.newLine; 267 | if (lang.equals("en_us")) 268 | return StatusCode.LOGGED + "-" + "" + Dict.newLine + "===------===" + Dict.newLine + ">>> :) Good " + GoodXX.getTimeAsWord() + ", " + username + "!" + Dict.newLine 269 | + ">>> LiteFTPD https://github.com/AdlerED/LiteFTPD-UNIX" + Dict.newLine + "===------===" + Dict.newLine 270 | + "IS THE CHINESE ON THE RIGHT NORMAL? -> 中文 <- If not, type \"quote gb\" to change the encode type." + Dict.newLine + "230 OK" + Dict.newLine; 271 | return null; 272 | } 273 | 274 | public static String tooMuchLoginInUser(String username) { 275 | if (lang.equals("zh_cn")) 276 | return StatusCode.NOTLOGIN + " 抱歉, 用户 \"" + username + "\" 连接数过多, 请稍候重试." + Dict.newLine; 277 | if (lang.equals("en_us")) 278 | return StatusCode.NOTLOGIN + " Sorry, user \"" + username + "\" has too much login, please try again at later." + Dict.newLine; 279 | return null; 280 | } 281 | 282 | public static String utf8(boolean status) { 283 | if (lang.equals("zh_cn")) { 284 | if (status) 285 | return StatusCode.SUCCESS + " OPTS UTF8 命令已执行 - UTF8 编码现在已开启." + Dict.newLine; 286 | else 287 | return StatusCode.SUCCESS + " OPTS UTF8 命令已执行 - UTF8 编码现在已停用." + Dict.newLine; 288 | } 289 | if (lang.equals("en_us")) { 290 | if (status) 291 | return StatusCode.SUCCESS + " OPTS UTF8 command successful - UTF8 encoding now ON." + Dict.newLine; 292 | else 293 | return StatusCode.SUCCESS + " OPTS UTF8 command successful - UTF8 encoding now OFF." + Dict.newLine; 294 | } 295 | return null; 296 | } 297 | 298 | public static String bye() { 299 | if (lang.equals("zh_cn")) 300 | return StatusCode.SERVICESTOP + " :) 再见!" + "" + Dict.newLine; 301 | if (lang.equals("en_us")) 302 | return StatusCode.SERVICESTOP + " :) See ya!" + "" + Dict.newLine; 303 | return null; 304 | } 305 | 306 | public static String passwordRequired(String username) { 307 | if (lang.equals("zh_cn")) 308 | return StatusCode.PASSREQ + " 请输入用户 " + username + " 的密码." + Dict.newLine; 309 | if (lang.equals("en_us")) 310 | return StatusCode.PASSREQ + " Password required for " + username + "." + Dict.newLine; 311 | return null; 312 | } 313 | 314 | public static String permissionDenied() { 315 | if (lang.equals("zh_cn")) 316 | return StatusCode.ERRTARGET + " 没有执行此操作的权限." + Dict.newLine; 317 | if (lang.equals("en_us")) 318 | return StatusCode.ERRTARGET + " Permission denied." + Dict.newLine; 319 | return null; 320 | } 321 | 322 | public static String transferCompleteInAsciiMode(long fileLength, long time, float averageTime) { 323 | if (lang.equals("zh_cn")) 324 | return StatusCode.CLOSED + "-传输完毕. " + fileLength + " 字节在 " + time + " 秒内传输完成. 平均 " + averageTime + " KB/秒." + Dict.newLine 325 | + StatusCode.CLOSED + " 你正在使用 ASCII 模式传输文件. 如果你的文件是损坏的, 输入 \"binary\" 然后再重试一次." + Dict.newLine; 326 | if (lang.equals("en_us")) 327 | return StatusCode.CLOSED + "-Transfer complete. " + fileLength + " bytes saved in " + time + " second. " + averageTime + " KB/sec." + Dict.newLine 328 | + StatusCode.CLOSED + " You are using ASCII mode to transfer files. If you find that the file is corrupt, type \"binary\" and try again." + Dict.newLine; 329 | return null; 330 | } 331 | 332 | public static String transferComplete(long fileLength, long time, float averageTime) { 333 | if (lang.equals("zh_cn")) 334 | return StatusCode.CLOSED + " 传输完毕. " + fileLength + " 字节在 " + time + " 秒内传输完毕. 平均 " + averageTime + " KB/秒." + Dict.newLine; 335 | if (lang.equals("en_us")) 336 | return StatusCode.CLOSED + " Transfer complete. " + fileLength + " bytes saved in " + time + " second. " + averageTime + " KB/sec." + Dict.newLine; 337 | return null; 338 | } 339 | 340 | public static String connectedMessage(String ip) { 341 | if (lang.equals("zh_cn")) 342 | return StatusCode.SERVICEREADY + "-LiteFTPD" + Dict.newLine + ">>> 请登录." + Dict.newLine + ">>> 你的IP地址: " + ip + Dict.newLine + "220" + " :) " + Variable.welcomeMessage + "" + Dict.newLine; 343 | if (lang.equals("en_us")) 344 | return StatusCode.SERVICEREADY + "-LiteFTPD" + Dict.newLine + ">>> Please log in." + Dict.newLine + ">>> Your IP address: " + ip + Dict.newLine + "220" + " :) " + Variable.welcomeMessage + "" + Dict.newLine; 345 | return null; 346 | } 347 | 348 | public static String closedInReason(String reason) { 349 | if (lang.equals("zh_cn")) 350 | return "LiteFTPD > :( 抱歉, 服务端已经关闭了连接! 原因: " + reason + "." + Dict.newLine; 351 | if (lang.equals("en_us")) 352 | return "LiteFTPD > :( Sorry, the connection is closed from server! Reason: " + reason + "." + Dict.newLine; 353 | return null; 354 | } 355 | 356 | public static String outOfOnlineLimit() { 357 | if (lang.equals("zh_cn")) 358 | return StatusCode.NOTLOGIN + " :( 在线用户数过多." + "" + Dict.newLine; 359 | if (lang.equals("en_us")) 360 | return StatusCode.NOTLOGIN + " :( Too much users online." + "" + Dict.newLine; 361 | return null; 362 | } 363 | 364 | public static String onlineStr() { 365 | if (lang.equals("zh_cn")) 366 | return "在线"; 367 | if (lang.equals("en_us")) 368 | return "Online"; 369 | return null; 370 | } 371 | 372 | public static String clearStr() { 373 | if (lang.equals("zh_cn")) 374 | return "清除"; 375 | if (lang.equals("en_us")) 376 | return "Clear"; 377 | return null; 378 | } 379 | 380 | public static String actionStr() { 381 | if (lang.equals("zh_cn")) 382 | return "操作"; 383 | if (lang.equals("en_us")) 384 | return "Action"; 385 | return null; 386 | } 387 | 388 | public static String connectionsStr() { 389 | if (lang.equals("zh_cn")) 390 | return "连接数"; 391 | if (lang.equals("en_us")) 392 | return "Connection"; 393 | return null; 394 | } 395 | 396 | public static String t() { 397 | if (lang.equals("zh_cn")) 398 | return ""; 399 | if (lang.equals("en_us")) 400 | return ""; 401 | return null; 402 | } 403 | 404 | public static final String newLine = "\r\n"; 405 | } 406 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/dict/StatusCode.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.dict; 2 | 3 | /** 4 | *Status code.
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-09-19 09:21 9 | **/ 10 | public class StatusCode { 11 | 12 | /** 13 | * Preliminary affirmative reply 14 | */ 15 | 16 | // Service is ready, will be start in ? min. 17 | public static final int READY = 120; 18 | // Data connection opened, transmission is starting. 19 | public static final int OPEN = 125; 20 | // File status OK, ready to open data connect. 21 | public static final int STATUSOK = 150; 22 | 23 | /** 24 | * A definite and complete answer 25 | */ 26 | 27 | // Command success. 28 | public static final int SUCCESS = 200; 29 | // Cannot execute command, too much command at the same time. 30 | public static final int MUCHCOMMAND = 202; 31 | // System status / System helping answer. 32 | public static final int STATUS = 211; 33 | // Directory status. 34 | public static final int DIRSTATUS = 212; 35 | // File status. 36 | public static final int FILESTATUS = 213; 37 | // Helping message. 38 | public static final int HELPING = 214; 39 | // NAME System type. 40 | public static final int NAME = 215; 41 | // Service is ready, can execute new user's request. 42 | public static final int SERVICEREADY = 220; 43 | // Service stopped control connection. 44 | public static final int SERVICESTOP = 221; 45 | // Data connection opened, no any transmission running. 46 | public static final int DATAOPEN = 225; 47 | // Data connection closed with successful. 48 | public static final int CLOSED = 226; 49 | // Enter passive mode. 50 | public static final int PASSIVE = 227; 51 | // User logged in. 52 | public static final int LOGGED = 230; 53 | // File request correct, done. 54 | public static final int CORRECT = 250; 55 | // Created "PATHNAME". 56 | public static final int CPATH = 257; 57 | 58 | /** 59 | * Intermediate affirmative response 60 | */ 61 | 62 | // Password required. 63 | public static final int PASSREQ = 331; 64 | // Need login. 65 | public static final int LOGIN = 332; 66 | // Waiting for file execution response. 67 | public static final int WAIT = 350; 68 | 69 | /** 70 | * Complete Answer to Transient Negation 71 | */ 72 | 73 | // Cannot open data connection. 74 | public static final int CANTOPEN = 425; 75 | // Connection closed; Transfer aborted. 76 | public static final int ABORTED = 426; 77 | //File unavailable。 78 | public static final int UNAVAILABLE = 450; 79 | //Processing local errors. 80 | public static final int ERRORS = 451; 81 | //Not enough storage space. 82 | public static final int OUTOFSPACE = 452; 83 | 84 | /** 85 | * Permanent negative completion reply 86 | */ 87 | 88 | //Command not understood. 89 | public static final int CMDUNKNOWN = 500; 90 | //A syntax error in the argument 91 | public static final int ERRSYNTAX = 501; 92 | //Command not executed. 93 | public static final int NOTRUN = 502; 94 | //Error command sequence. 95 | public static final int ERRSEQUENCE = 503; 96 | //Command arguments not executed. 97 | public static final int ERRARGS = 504; 98 | //Not logged in. 99 | public static final int NOTLOGIN = 530; 100 | //Need account while uploading files. 101 | public static final int NEEDACCOUNT = 532; 102 | //File not found / no permission. 103 | public static final int ERRTARGET = 550; 104 | //Unknown type of the page. 105 | public static final int UNTYPE = 551; 106 | //Out of storage space distribution. 107 | public static final int OUTSPACELIMIT = 552; 108 | //Filename not allowed. 109 | public static final int INVALIDFILENAME = 553; 110 | } 111 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/graphic/main/GraphicMain.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.graphic.main; 2 | 3 | import pers.adlered.liteftpd.dict.Dict; 4 | import pers.adlered.liteftpd.graphic.main.model.MainModels; 5 | import pers.adlered.liteftpd.graphic.update.RunningUpdate; 6 | 7 | import javax.swing.*; 8 | import javax.swing.border.Border; 9 | import javax.swing.border.EmptyBorder; 10 | import java.awt.*; 11 | import java.awt.event.ActionEvent; 12 | import java.awt.event.ActionListener; 13 | 14 | /** 15 | *图形界面初始类
17 | * 18 | * @author : https://github.com/AdlerED 19 | * @date : 2019-10-06 21:55 20 | **/ 21 | public class GraphicMain extends JFrame implements Runnable, ActionListener { 22 | // Options 23 | JMenuItem clear = null; 24 | 25 | @Override 26 | public void run() { 27 | // Initialize 28 | setSize(800, 340); 29 | setLocationRelativeTo(null); 30 | setTitle("LiteFTPD-UNIX"); 31 | setLayout(new BorderLayout()); 32 | // Panel 33 | JPanel westPanel = new JPanel(new BorderLayout()); 34 | JPanel eastPanel = new JPanel(new BorderLayout()); 35 | // Console 36 | MainModels.console.setEditable(false); 37 | JScrollPane scrollPane = new JScrollPane(MainModels.console); 38 | scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 39 | scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 40 | // Menu bar 41 | JMenuBar jMenuBar = new JMenuBar(); 42 | JMenu action = new JMenu(Dict.actionStr()); 43 | 44 | clear = new JMenuItem(Dict.clearStr()); 45 | clear.addActionListener(this); 46 | action.add(clear); 47 | 48 | jMenuBar.add(action); 49 | // Data 50 | MainModels.data.setEditable(false); 51 | MainModels.console.setLineWrap(true); 52 | JScrollPane dataPane = new JScrollPane(MainModels.data); 53 | dataPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 54 | dataPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 55 | // Add Models 56 | westPanel.add(scrollPane, BorderLayout.NORTH); 57 | eastPanel.add(dataPane, BorderLayout.NORTH); 58 | // Add Panels 59 | add(jMenuBar, BorderLayout.NORTH); 60 | add(westPanel, BorderLayout.WEST); 61 | add(eastPanel, BorderLayout.EAST); 62 | // Must the end 63 | setVisible(true); 64 | MainModels.guiReady = true; 65 | // Data update 66 | Thread dataUpdateThread = new Thread(new RunningUpdate()); 67 | dataUpdateThread.start(); 68 | } 69 | 70 | @Override 71 | public void actionPerformed(ActionEvent e) { 72 | if (e.getSource() == clear) { 73 | MainModels.console.setText(""); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/graphic/main/model/MainModels.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.graphic.main.model; 2 | 3 | import javax.swing.*; 4 | 5 | /** 6 | *存放主界面控件
8 | * 9 | * @author : https://github.com/AdlerED 10 | * @date : 2019-10-06 22:14 11 | **/ 12 | public class MainModels { 13 | public static boolean guiReady = false; 14 | 15 | public static JTextArea console = new JTextArea(18, 31); 16 | public static JTextArea data = new JTextArea(3, 32); 17 | } 18 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/graphic/update/RunningUpdate.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.graphic.update; 2 | 3 | import pers.adlered.liteftpd.dict.Dict; 4 | import pers.adlered.liteftpd.graphic.main.model.MainModels; 5 | import pers.adlered.liteftpd.logger.Logger; 6 | import pers.adlered.liteftpd.logger.enums.Levels; 7 | import pers.adlered.liteftpd.logger.enums.Types; 8 | import pers.adlered.liteftpd.user.status.Online; 9 | import pers.adlered.liteftpd.user.status.bind.UserLimitBind; 10 | 11 | import java.util.*; 12 | 13 | /** 14 | *实时更新数据,并显示在界面上
16 | * 17 | * @author : https://github.com/AdlerED 18 | * @date : 2019-10-06 22:55 19 | **/ 20 | public class RunningUpdate implements Runnable { 21 | @Override 22 | public void run() { 23 | try { 24 | while (true) { 25 | ListWhen Logger received a log, Filter will check it's level to decide display or not.
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-09-19 15:17 12 | **/ 13 | public class Filter { 14 | public static boolean fil(Levels level) { 15 | boolean status = false; 16 | switch (level) { 17 | case DEBUG: 18 | if (Variable.debugLevel >= 4) { 19 | status = true; 20 | } 21 | break; 22 | case ERROR: 23 | if (Variable.debugLevel >= 3) { 24 | status = true; 25 | } 26 | break; 27 | case WARN: 28 | if (Variable.debugLevel >= 2) { 29 | status = true; 30 | } 31 | break; 32 | case INFO: 33 | if (Variable.debugLevel >= 1) { 34 | status = true; 35 | } 36 | break; 37 | } 38 | return status; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/logger/Logger.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.logger; 2 | 3 | import pers.adlered.liteftpd.graphic.main.model.MainModels; 4 | import pers.adlered.liteftpd.logger.enums.Levels; 5 | import pers.adlered.liteftpd.logger.enums.Types; 6 | 7 | /** 8 | *All logs will through here.
10 | * 11 | * @author : https://github.com/AdlerED 12 | * @date : 2019-09-19 15:18 13 | **/ 14 | public class Logger { 15 | public static boolean log(Types type, Levels level, String log) { 16 | if (Filter.fil(level)) { 17 | // Can be logged 18 | System.out.println("[" + level + "]" + " " + "[" + type + "]" + " >> " + log); 19 | if (MainModels.guiReady) { 20 | MainModels.console.append("[" + level + "]" + " " + "[" + type + "]" + " >> " + log + "\n"); 21 | MainModels.console.setCaretPosition(MainModels.console.getDocument().getLength()); 22 | } 23 | return true; 24 | } else { 25 | // Cannot log 26 | return false; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/logger/enums/Levels.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.logger.enums; 2 | 3 | public enum Levels { 4 | ERROR, WARN, INFO, DEBUG 5 | } 6 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/logger/enums/Types.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.logger.enums; 2 | 3 | public enum Types { 4 | /* 5 | SYS: System message; 6 | RECV: Receive task status; 7 | SEND: Send task status; 8 | TRANS: Transition task status; 9 | */ 10 | SYS, RECV, SEND, TRANS 11 | } 12 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/main/Main.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.main; 2 | 3 | import pers.adlered.liteftpd.dict.Dict; 4 | import pers.adlered.liteftpd.graphic.main.GraphicMain; 5 | import pers.adlered.liteftpd.logger.enums.Levels; 6 | import pers.adlered.liteftpd.logger.Logger; 7 | import pers.adlered.liteftpd.logger.enums.Types; 8 | import pers.adlered.liteftpd.pool.handler.HandlerPool; 9 | import pers.adlered.liteftpd.tool.ConsoleTable; 10 | import pers.adlered.liteftpd.tool.LocalAddress; 11 | import pers.adlered.liteftpd.tool.Status; 12 | import pers.adlered.liteftpd.user.User; 13 | import pers.adlered.liteftpd.user.status.Online; 14 | import pers.adlered.liteftpd.user.status.bind.IpLimitBind; 15 | import pers.adlered.liteftpd.user.status.bind.SpeedLimitBind; 16 | import pers.adlered.liteftpd.user.verify.OnlineRules; 17 | import pers.adlered.liteftpd.variable.OnlineUserController; 18 | import pers.adlered.liteftpd.variable.Variable; 19 | import pers.adlered.liteftpd.wizard.config.Prop; 20 | import pers.adlered.liteftpd.wizard.init.SocketHandler; 21 | 22 | import java.io.BufferedOutputStream; 23 | import java.io.IOException; 24 | import java.net.ServerSocket; 25 | import java.net.Socket; 26 | 27 | /** 28 | *Main method of LiteFTPD, listening connections and create a new thread into thread pool.
30 | * 31 | * @author : https://github.com/AdlerED 32 | * @date : 2019-09-19 09:21 33 | **/ 34 | public class Main { 35 | public static void main(String[] args) { 36 | Main.init(args); 37 | ServerSocket serverSocket = null; 38 | try { 39 | Logger.log(Types.SYS, Levels.INFO, "LiteFTPD by AdlerED <- GitHub"); 40 | // Listen socket connections, handle with SocketHandler. 41 | serverSocket = new ServerSocket(Variable.port); 42 | Logger.log(Types.SYS, Levels.INFO, "Listening " + serverSocket.getLocalSocketAddress()); 43 | Logger.log(Types.SYS, Levels.INFO, "You can connect to the FTP Server via following IP address:"); 44 | ConsoleTable consoleTable = new ConsoleTable(LocalAddress.getLocalIPList().size(), true); 45 | consoleTable.appendRow(); 46 | consoleTable.appendColum("Listening IP:Port") 47 | .appendColum("github.com/AdlerED"); 48 | consoleTable.appendRow(); 49 | if (Variable.debugLevel >= 1) { 50 | for (String i : LocalAddress.getLocalIPList()) { 51 | consoleTable.appendColum(i + ":" + serverSocket.getLocalPort()); 52 | } 53 | } 54 | Logger.log(Types.SYS, Levels.INFO, "\n" + consoleTable.toString()); 55 | } catch (IOException IOE) { 56 | // TODO 57 | IOE.printStackTrace(); 58 | } 59 | while (true) { 60 | try { 61 | Logger.log(Types.SYS, Levels.INFO, "Memory used: " + Status.memoryUsed()); 62 | Socket socket = serverSocket.accept(); 63 | // Online limit checking 64 | String hostAdd = socket.getInetAddress().getHostAddress(); 65 | IpLimitBind ipLimitBind = OnlineRules.checkIpAddress(hostAdd); 66 | if (((ipLimitBind.getIp() == null) || Variable.online >= Variable.maxUserLimit) && Variable.maxUserLimit != 0) { 67 | for (int i = 0; i < Online.ipRuleOnline.size(); i++) { 68 | if (Online.ipRuleOnline.get(i).getIp().equals(hostAdd)) { 69 | Online.ipRuleOnline.remove(i); 70 | break; 71 | } 72 | } 73 | BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); 74 | bufferedOutputStream.write(Dict.outOfOnlineLimit().getBytes()); 75 | bufferedOutputStream.flush(); 76 | bufferedOutputStream.close(); 77 | socket.close(); 78 | } else { 79 | HandlerPool.handlerPool.execute(new SocketHandler(socket, ipLimitBind)); 80 | OnlineUserController.printOnline(); 81 | } 82 | } catch (IOException IOE) { 83 | // TODO 84 | IOE.printStackTrace(); 85 | } 86 | } 87 | } 88 | 89 | public static void init(String[] args) { 90 | // 设置LiteFTPD关闭时的操作 91 | Runtime runtime = Runtime.getRuntime(); 92 | runtime.addShutdownHook(new Thread() { 93 | @Override 94 | public void run() { 95 | Logger.log(Types.SYS, Levels.INFO, "LiteFTPD stopped."); 96 | } 97 | }); 98 | // 读取配置文件 99 | Prop.getInstance(); 100 | // 检测传值,执行指定操作 101 | for (int i = 0; i < args.length; i++) { 102 | String variable = args[i]; 103 | if (variable.equals("-l")) { 104 | String value = args[i + 1]; 105 | value = value.replaceAll("-", "_"); 106 | if (value.equals("en_us")) { 107 | Logger.log(Types.SYS, Levels.INFO, "Language option detected. Init language as \"English\"."); 108 | Dict.init(value); 109 | } else if (value.equals("zh_cn")) { 110 | Logger.log(Types.SYS, Levels.INFO, "Language option detected. Init language as \"简体中文\"."); 111 | Dict.init(value); 112 | } else { 113 | Logger.log(Types.SYS, Levels.WARN, "Cannot support customize language \"" + value + "\". Using default \"English\"."); 114 | Logger.log(Types.SYS, Levels.WARN, "Supported language: zh_cn en_us"); 115 | } 116 | } else if (variable.equals("-g")) { 117 | Logger.log(Types.SYS, Levels.INFO, "Launching graphic interface..."); 118 | Thread GUI = new Thread(new GraphicMain()); 119 | GUI.run(); 120 | } 121 | } 122 | // 初始化用户信息 123 | User.initUsers(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/mode/PASV.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.mode; 2 | 3 | import pers.adlered.liteftpd.analyze.PrivateVariable; 4 | import pers.adlered.liteftpd.dict.Dict; 5 | import pers.adlered.liteftpd.logger.enums.Levels; 6 | import pers.adlered.liteftpd.logger.Logger; 7 | import pers.adlered.liteftpd.logger.enums.Types; 8 | import pers.adlered.liteftpd.user.status.bind.SpeedLimitBind; 9 | import pers.adlered.liteftpd.wizard.init.PauseListen; 10 | import pers.adlered.liteftpd.wizard.init.Send; 11 | import pers.adlered.liteftpd.variable.Variable; 12 | 13 | import java.io.*; 14 | import java.net.BindException; 15 | import java.net.ServerSocket; 16 | import java.net.Socket; 17 | import java.net.SocketException; 18 | 19 | /** 20 | *Passive mode.
22 | * 23 | * @author : https://github.com/AdlerED 24 | * @date : 2019-09-19 09:21 25 | **/ 26 | public class PASV extends Thread { 27 | private ServerSocket serverSocket = null; 28 | private Socket socket = null; 29 | private Send send = null; 30 | private PrivateVariable privateVariable = null; 31 | private PauseListen pauseListen = null; 32 | 33 | private String listening = null; 34 | private File file = null; 35 | private String path = null; 36 | private SpeedLimitBind speedLimitBind = null; 37 | 38 | private boolean isASCII = true; 39 | 40 | public PASV(Send send, PrivateVariable privateVariable, PauseListen pauseListen, String type, SpeedLimitBind speedLimitBind) { 41 | this.send = send; 42 | this.privateVariable = privateVariable; 43 | this.pauseListen = pauseListen; 44 | if (type.equals("I")) { 45 | isASCII = false; 46 | } 47 | this.speedLimitBind = speedLimitBind; 48 | } 49 | 50 | public boolean listen(int port) { 51 | boolean result = true; 52 | try { 53 | ServerSocket serverSocket = new ServerSocket(port); 54 | Logger.log(Types.SYS, Levels.DEBUG, "Listening " + port + "..."); 55 | this.serverSocket = serverSocket; 56 | } catch (BindException BE) { 57 | result = false; 58 | } catch (IOException IOE) { 59 | result = false; 60 | } 61 | return result; 62 | } 63 | 64 | @Override 65 | public void run() { 66 | try { 67 | Logger.log(Types.SYS, Levels.DEBUG, "Transmitter is waiting the port " + serverSocket.getLocalPort() + " for the client."); 68 | Socket socket = serverSocket.accept(); 69 | this.socket = socket; 70 | Logger.log(Types.SYS, Levels.DEBUG, "Connected. Waiting for " + socket.getRemoteSocketAddress() + "..."); 71 | try { 72 | while (listening == null && file == null && path == null) { 73 | if (!pauseListen.isRunning()) { 74 | Logger.log(Types.SYS, Levels.WARN, "Passive mode listener paused."); 75 | break; 76 | } 77 | Thread.sleep(5); 78 | } 79 | } catch (InterruptedException IE) { 80 | } 81 | privateVariable.setTimeoutLock(true); 82 | if (pauseListen.isRunning()) { 83 | // 开始传输 84 | Logger.log(Types.SYS, Levels.DEBUG, "Service has response."); 85 | long startTime = System.currentTimeMillis(); 86 | float kb = 0; 87 | long bts = 0; 88 | if (listening != null) { 89 | // To avoid bare line feeds. 90 | BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); 91 | listening = listening.replaceAll("" + Dict.newLine, "\n"); 92 | listening = listening.replaceAll("\n", "" + Dict.newLine); 93 | if (Variable.smartEncode) { 94 | bufferedOutputStream.write(listening.getBytes(privateVariable.encode)); 95 | } else { 96 | bufferedOutputStream.write(listening.getBytes(Variable.defaultEncode)); 97 | } 98 | bufferedOutputStream.flush(); 99 | bufferedOutputStream.close(); 100 | bts = (listening.getBytes(privateVariable.encode)).length; 101 | } else if (file != null) { 102 | if (speedLimitBind.getDownloadSpeed() != 0) { 103 | FileInputStream fileInputStream = new FileInputStream(file); 104 | OutputStream outputStream = new DataOutputStream(socket.getOutputStream()); 105 | byte[] bytes = new byte[speedLimitBind.getDownloadSpeed() * 1024]; 106 | int len = -1; 107 | if (privateVariable.getRest() == 0l) { 108 | if (!isASCII) { 109 | // Not rest mode 110 | while ((len = fileInputStream.read(bytes)) != -1) { 111 | outputStream.write(bytes, 0, len); 112 | Thread.sleep(1000); 113 | } 114 | outputStream.flush(); 115 | fileInputStream.close(); 116 | outputStream.close(); 117 | bts = file.length(); 118 | } else { 119 | FileReader fileReader = new FileReader(file); 120 | BufferedReader bufferedReader = new BufferedReader(fileReader); 121 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); 122 | int length = -1; 123 | char[] chars = new char[speedLimitBind.getUploadSpeed() * 1024]; 124 | while ((length = bufferedReader.read(chars)) != -1) { 125 | outputStreamWriter.write(String.valueOf(chars, 0, length).replaceAll("\r", "").replaceAll("\n", "\r\n")); 126 | Thread.sleep(1000); 127 | } 128 | outputStreamWriter.flush(); 129 | fileReader.close(); 130 | outputStreamWriter.close(); 131 | outputStream.close(); 132 | bts = file.length(); 133 | } 134 | } else { 135 | // Rest mode on 136 | fileInputStream.skip(privateVariable.getRest()); 137 | while ((len = fileInputStream.read(bytes)) != -1) { 138 | outputStream.write(bytes, 0, len); 139 | Thread.sleep(1000); 140 | } 141 | outputStream.flush(); 142 | fileInputStream.close(); 143 | outputStream.close(); 144 | bts = file.length() - privateVariable.getRest(); 145 | privateVariable.resetRest(); 146 | } 147 | } else { 148 | FileInputStream fileInputStream = new FileInputStream(file); 149 | OutputStream outputStream = new DataOutputStream(socket.getOutputStream()); 150 | byte[] bytes = new byte[8192]; 151 | int len = -1; 152 | if (privateVariable.getRest() == 0l) { 153 | if (!isASCII) { 154 | // Not rest mode 155 | while ((len = fileInputStream.read(bytes)) != -1) { 156 | outputStream.write(bytes, 0, len); 157 | } 158 | outputStream.flush(); 159 | fileInputStream.close(); 160 | outputStream.close(); 161 | bts = file.length(); 162 | } else { 163 | FileReader fileReader = new FileReader(file); 164 | BufferedReader bufferedReader = new BufferedReader(fileReader); 165 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); 166 | String line; 167 | while ((line = bufferedReader.readLine()) != null) { 168 | outputStreamWriter.write(line + "\r\n"); 169 | } 170 | outputStreamWriter.flush(); 171 | fileReader.close(); 172 | outputStreamWriter.close(); 173 | outputStream.close(); 174 | bts = file.length(); 175 | } 176 | } else { 177 | // Rest mode on 178 | fileInputStream.skip(privateVariable.getRest()); 179 | while ((len = fileInputStream.read(bytes)) != -1) { 180 | outputStream.write(bytes, 0, len); 181 | } 182 | outputStream.flush(); 183 | fileInputStream.close(); 184 | outputStream.close(); 185 | bts = file.length() - privateVariable.getRest(); 186 | privateVariable.resetRest(); 187 | } 188 | } 189 | } else if (path != null) { 190 | Logger.log(Types.RECV, Levels.DEBUG, "Passive mode store. Path: " + path); 191 | File file = new File(path); 192 | if (!file.getParentFile().exists()) { 193 | file.getParentFile().mkdirs(); 194 | } 195 | FileOutputStream fileOutputStream = null; 196 | if (privateVariable.getRest() == 0l) { 197 | boolean deleted = file.delete(); 198 | Logger.log(Types.RECV, Levels.DEBUG, "The file is already exists but deleted: " + deleted); 199 | fileOutputStream = new FileOutputStream(file, false); 200 | } else { 201 | Logger.log(Types.RECV, Levels.DEBUG, "Continue file receive."); 202 | fileOutputStream = new FileOutputStream(file, true); 203 | } 204 | // FileOutputStream will be create a new file auto. 205 | if (speedLimitBind.getUploadSpeed() == 0) { 206 | if (!isASCII) { 207 | try { 208 | InputStream inputStream = socket.getInputStream(); 209 | byte[] bytes = new byte[8192]; 210 | int len = -1; 211 | long sTime = System.currentTimeMillis(); 212 | while ((len = inputStream.read(bytes)) != -1) { 213 | fileOutputStream.write(bytes, 0, len); 214 | } 215 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 216 | if (eTime == 0) eTime = 1; 217 | float pSecond = file.length() / eTime; 218 | fileOutputStream.flush(); 219 | send.send(Dict.transferComplete(file.length(), eTime, pSecond)); 220 | inputStream.close(); 221 | fileOutputStream.close(); 222 | } catch (FileNotFoundException FNFE) { 223 | send.send(Dict.permissionDenied()); 224 | FNFE.printStackTrace(); 225 | } 226 | } else { 227 | try { 228 | FileWriter fileWriter = new FileWriter(file); 229 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 230 | InputStream inputStream = socket.getInputStream(); 231 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 232 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 233 | String line; 234 | long sTime = System.currentTimeMillis(); 235 | while ((line = bufferedReader.readLine()) != null) { 236 | bufferedWriter.write(line + "\n"); 237 | } 238 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 239 | if (eTime == 0) eTime = 1; 240 | float pSecond = file.length() / eTime; 241 | bufferedWriter.flush(); 242 | send.send(Dict.transferCompleteInAsciiMode(file.length(), eTime, pSecond)); 243 | bufferedReader.close(); 244 | inputStreamReader.close(); 245 | inputStream.close(); 246 | bufferedWriter.close(); 247 | fileWriter.close(); 248 | } catch (FileNotFoundException FNFE) { 249 | send.send(Dict.permissionDenied()); 250 | FNFE.printStackTrace(); 251 | } 252 | } 253 | } else { 254 | if (!isASCII) { 255 | try { 256 | InputStream inputStream = socket.getInputStream(); 257 | BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream, speedLimitBind.getUploadSpeed() * 1024); 258 | int len = -1; 259 | long sTime = System.currentTimeMillis(); 260 | byte[] bytes = new byte[speedLimitBind.getUploadSpeed() * 1024]; 261 | while ((len = bufferedInputStream.read(bytes)) != -1) { 262 | fileOutputStream.write(bytes, 0, len); 263 | Thread.sleep(1000); 264 | } 265 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 266 | if (eTime == 0) eTime = 1; 267 | float pSecond = file.length() / eTime; 268 | fileOutputStream.flush(); 269 | send.send(Dict.transferComplete(file.length(), eTime, pSecond)); 270 | inputStream.close(); 271 | fileOutputStream.close(); 272 | } catch (FileNotFoundException FNFE) { 273 | send.send(Dict.permissionDenied()); 274 | FNFE.printStackTrace(); 275 | } 276 | } else { 277 | try { 278 | FileWriter fileWriter = new FileWriter(file); 279 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 280 | InputStream inputStream = socket.getInputStream(); 281 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 282 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 283 | int len = -1; 284 | long sTime = System.currentTimeMillis(); 285 | char[] chars = new char[speedLimitBind.getUploadSpeed() * 1024]; 286 | while ((len = bufferedReader.read(chars)) != -1) { 287 | bufferedWriter.write(String.valueOf(chars, 0, len).replaceAll("\r\n", "\n")); 288 | Thread.sleep(1000); 289 | } 290 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 291 | if (eTime == 0) eTime = 1; 292 | float pSecond = file.length() / eTime; 293 | bufferedWriter.flush(); 294 | send.send(Dict.transferCompleteInAsciiMode(file.length(), eTime, pSecond)); 295 | bufferedReader.close(); 296 | inputStreamReader.close(); 297 | inputStream.close(); 298 | bufferedWriter.close(); 299 | fileWriter.close(); 300 | } catch (FileNotFoundException FNFE) { 301 | send.send(Dict.permissionDenied()); 302 | FNFE.printStackTrace(); 303 | } 304 | } 305 | } 306 | privateVariable.resetRest(); 307 | } 308 | if (path != null) { 309 | socket.close(); 310 | serverSocket.close(); 311 | } else { 312 | kb = bts / 1000; 313 | socket.close(); 314 | serverSocket.close(); 315 | long endTime = (System.currentTimeMillis() - startTime) / 1000; 316 | if (endTime == 0) endTime = 1; 317 | float perSecond = kb / endTime; 318 | if (isASCII && listening == null) { 319 | send.send(Dict.transferCompleteInAsciiMode(bts, endTime, perSecond)); 320 | } else { 321 | send.send(Dict.transferComplete(bts, endTime, perSecond)); 322 | } 323 | } 324 | } 325 | } catch (SocketException SE) { 326 | Logger.log(Types.SYS, Levels.ERROR, "Listening stopped."); 327 | } catch (IOException IOE) { 328 | // TODO 329 | IOE.printStackTrace(); 330 | } catch (Exception E) { 331 | E.printStackTrace(); 332 | } finally { 333 | if (pauseListen.isRunning()) { 334 | privateVariable.setTimeoutLock(false); 335 | } 336 | send = null; 337 | privateVariable = null; 338 | pauseListen = null; 339 | serverSocket = null; 340 | socket = null; 341 | listening = null; 342 | file = null; 343 | Logger.log(Types.SYS, Levels.DEBUG, "PASV Closed."); 344 | } 345 | } 346 | 347 | public void hello(String message) { 348 | listening = message; 349 | } 350 | 351 | public void hello(File file) { 352 | this.file = file; 353 | } 354 | 355 | public void helloSTOR(String path) { 356 | this.path = path; 357 | } 358 | 359 | public void stopSocket() { 360 | try { 361 | serverSocket.close(); 362 | socket.shutdownInput(); 363 | socket.shutdownOutput(); 364 | socket.close(); 365 | Logger.log(Types.SYS, Levels.DEBUG, "Server socket on " + serverSocket.getLocalSocketAddress() + "stopped."); 366 | } catch (IOException IOE) { 367 | IOE.printStackTrace(); 368 | } catch (NullPointerException NPE) { 369 | Logger.log(Types.SYS, Levels.WARN, "Latest passive port not connected. Closing forced."); 370 | } 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/mode/PORT.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.mode; 2 | 3 | import pers.adlered.liteftpd.analyze.PrivateVariable; 4 | import pers.adlered.liteftpd.dict.Dict; 5 | import pers.adlered.liteftpd.logger.enums.Levels; 6 | import pers.adlered.liteftpd.logger.Logger; 7 | import pers.adlered.liteftpd.logger.enums.Types; 8 | import pers.adlered.liteftpd.user.status.bind.SpeedLimitBind; 9 | import pers.adlered.liteftpd.wizard.init.PauseListen; 10 | import pers.adlered.liteftpd.wizard.init.Send; 11 | import pers.adlered.liteftpd.variable.Variable; 12 | 13 | import java.io.*; 14 | import java.net.Socket; 15 | import java.net.SocketException; 16 | import java.net.UnknownHostException; 17 | 18 | /** 19 | *Passive mode.
21 | * 22 | * @author : https://github.com/AdlerED 23 | * @date : 2019-09-19 09:21 24 | **/ 25 | public class PORT extends Thread { 26 | private Socket socket = null; 27 | private Send send = null; 28 | private PrivateVariable privateVariable = null; 29 | private PauseListen pauseListen = null; 30 | 31 | private String listening = null; 32 | private File file = null; 33 | private String path = null; 34 | private String ip = null; 35 | 36 | private int port = -1; 37 | private boolean isASCII = true; 38 | SpeedLimitBind speedLimitBind = null; 39 | 40 | public PORT(Send send, PrivateVariable privateVariable, PauseListen pauseListen, String type, SpeedLimitBind speedLimitBind) { 41 | this.send = send; 42 | this.privateVariable = privateVariable; 43 | this.pauseListen = pauseListen; 44 | if (type.equals("I")) { 45 | isASCII = false; 46 | } 47 | this.speedLimitBind = speedLimitBind; 48 | } 49 | 50 | public void setTarget(String ip, int port) { 51 | this.ip = ip; 52 | this.port = port; 53 | } 54 | 55 | private boolean connect() { 56 | boolean result = true; 57 | try { 58 | Logger.log(Types.SYS, Levels.DEBUG, "Connecting to " + ip + ":" + port + "..."); 59 | Socket socket = new Socket(ip, port); 60 | this.socket = socket; 61 | } catch (UnknownHostException UHE) { 62 | result = false; 63 | } catch (IllegalArgumentException IAE) { 64 | result = false; 65 | } catch (IOException IOE) { 66 | result = false; 67 | } 68 | return result; 69 | } 70 | 71 | @Override 72 | public void run() { 73 | if (connect()) { 74 | try { 75 | Logger.log(Types.SYS, Levels.DEBUG, "Connected. Translating with " + socket.getLocalSocketAddress() + " to " + socket.getRemoteSocketAddress() + "..."); 76 | privateVariable.setTimeoutLock(true); 77 | if (pauseListen.isRunning()) { 78 | Logger.log(Types.SYS, Levels.DEBUG, "Port mode is in transmission."); 79 | long startTime = System.currentTimeMillis(); 80 | float kb = 0; 81 | long bts = 0; 82 | if (listening != null) { 83 | // To avoid bare line feeds. 84 | BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); 85 | listening = listening.replaceAll("" + Dict.newLine, "\n"); 86 | listening = listening.replaceAll("\n", "" + Dict.newLine); 87 | if (Variable.smartEncode) { 88 | bufferedOutputStream.write(listening.getBytes(privateVariable.encode)); 89 | } else { 90 | bufferedOutputStream.write(listening.getBytes(Variable.defaultEncode)); 91 | } 92 | bufferedOutputStream.flush(); 93 | bufferedOutputStream.close(); 94 | bts = (listening.getBytes(privateVariable.encode)).length; 95 | } else if (file != null) { 96 | if (speedLimitBind.getDownloadSpeed() != 0) { 97 | FileInputStream fileInputStream = new FileInputStream(file); 98 | OutputStream outputStream = new DataOutputStream(socket.getOutputStream()); 99 | byte[] bytes = new byte[speedLimitBind.getDownloadSpeed() * 1024]; 100 | int len = -1; 101 | if (privateVariable.getRest() == 0l) { 102 | if (!isASCII) { 103 | // Not rest mode 104 | while ((len = fileInputStream.read(bytes)) != -1) { 105 | outputStream.write(bytes, 0, len); 106 | Thread.sleep(1000); 107 | } 108 | outputStream.flush(); 109 | fileInputStream.close(); 110 | outputStream.close(); 111 | bts = file.length(); 112 | } else { 113 | FileReader fileReader = new FileReader(file); 114 | BufferedReader bufferedReader = new BufferedReader(fileReader); 115 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); 116 | int length = -1; 117 | char[] chars = new char[speedLimitBind.getUploadSpeed() * 1024]; 118 | while ((length = bufferedReader.read(chars)) != -1) { 119 | outputStreamWriter.write(String.valueOf(chars, 0, length).replaceAll("\r", "").replaceAll("\n", "\r\n")); 120 | Thread.sleep(1000); 121 | } 122 | outputStreamWriter.flush(); 123 | fileReader.close(); 124 | outputStreamWriter.close(); 125 | outputStream.close(); 126 | bts = file.length(); 127 | } 128 | } else { 129 | // Rest mode on 130 | fileInputStream.skip(privateVariable.getRest()); 131 | while ((len = fileInputStream.read(bytes)) != -1) { 132 | outputStream.write(bytes, 0, len); 133 | Thread.sleep(1000); 134 | } 135 | outputStream.flush(); 136 | fileInputStream.close(); 137 | outputStream.close(); 138 | bts = file.length() - privateVariable.getRest(); 139 | privateVariable.resetRest(); 140 | } 141 | } else { 142 | FileInputStream fileInputStream = new FileInputStream(file); 143 | OutputStream outputStream = new DataOutputStream(socket.getOutputStream()); 144 | byte[] bytes = new byte[8192]; 145 | int len = -1; 146 | if (privateVariable.getRest() == 0l) { 147 | if (!isASCII) { 148 | // Not rest mode 149 | while ((len = fileInputStream.read(bytes)) != -1) { 150 | outputStream.write(bytes, 0, len); 151 | } 152 | outputStream.flush(); 153 | fileInputStream.close(); 154 | outputStream.close(); 155 | bts = file.length(); 156 | } else { 157 | FileReader fileReader = new FileReader(file); 158 | BufferedReader bufferedReader = new BufferedReader(fileReader); 159 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); 160 | String line; 161 | while ((line = bufferedReader.readLine()) != null) { 162 | outputStreamWriter.write(line + "\r\n"); 163 | } 164 | outputStreamWriter.flush(); 165 | fileReader.close(); 166 | outputStreamWriter.close(); 167 | outputStream.close(); 168 | bts = file.length(); 169 | } 170 | } else { 171 | // Rest mode on 172 | fileInputStream.skip(privateVariable.getRest()); 173 | while ((len = fileInputStream.read(bytes)) != -1) { 174 | outputStream.write(bytes, 0, len); 175 | } 176 | outputStream.flush(); 177 | fileInputStream.close(); 178 | outputStream.close(); 179 | bts = file.length() - privateVariable.getRest(); 180 | privateVariable.resetRest(); 181 | } 182 | } 183 | } else if (path != null) { 184 | Logger.log(Types.RECV, Levels.DEBUG, "Port mode store. Path: " + path); 185 | File file = new File(path); 186 | if (!file.getParentFile().exists()) { 187 | file.getParentFile().mkdirs(); 188 | } 189 | FileOutputStream fileOutputStream = null; 190 | if (privateVariable.getRest() == 0l) { 191 | boolean deleted = file.delete(); 192 | Logger.log(Types.RECV, Levels.DEBUG, "The file is already exists but deleted: " + deleted); 193 | fileOutputStream = new FileOutputStream(file, false); 194 | } else { 195 | Logger.log(Types.RECV, Levels.DEBUG, "Continue file receive."); 196 | fileOutputStream = new FileOutputStream(file, true); 197 | } 198 | // FileOutputStream will be create a new file auto. 199 | if (speedLimitBind.getUploadSpeed() == 0) { 200 | if (!isASCII) { 201 | try { 202 | InputStream inputStream = socket.getInputStream(); 203 | byte[] bytes = new byte[8192]; 204 | int len = -1; 205 | long sTime = System.currentTimeMillis(); 206 | while ((len = inputStream.read(bytes)) != -1) { 207 | fileOutputStream.write(bytes, 0, len); 208 | } 209 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 210 | if (eTime == 0) eTime = 1; 211 | float pSecond = file.length() / eTime; 212 | fileOutputStream.flush(); 213 | send.send(Dict.transferComplete(file.length(), eTime, pSecond)); 214 | inputStream.close(); 215 | fileOutputStream.close(); 216 | } catch (FileNotFoundException FNFE) { 217 | send.send(Dict.permissionDenied()); 218 | FNFE.printStackTrace(); 219 | } 220 | } else { 221 | try { 222 | FileWriter fileWriter = new FileWriter(file); 223 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 224 | InputStream inputStream = socket.getInputStream(); 225 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 226 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 227 | String line; 228 | long sTime = System.currentTimeMillis(); 229 | while ((line = bufferedReader.readLine()) != null) { 230 | bufferedWriter.write(line + "\n"); 231 | } 232 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 233 | if (eTime == 0) eTime = 1; 234 | float pSecond = file.length() / eTime; 235 | bufferedWriter.flush(); 236 | send.send(Dict.transferCompleteInAsciiMode(file.length(), eTime, pSecond)); 237 | bufferedReader.close(); 238 | inputStreamReader.close(); 239 | inputStream.close(); 240 | bufferedWriter.close(); 241 | fileWriter.close(); 242 | } catch (FileNotFoundException FNFE) { 243 | send.send(Dict.permissionDenied()); 244 | FNFE.printStackTrace(); 245 | } 246 | } 247 | } else { 248 | if (!isASCII) { 249 | try { 250 | InputStream inputStream = socket.getInputStream(); 251 | BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream, speedLimitBind.getUploadSpeed() * 1024); 252 | int len = -1; 253 | long sTime = System.currentTimeMillis(); 254 | byte[] bytes = new byte[speedLimitBind.getUploadSpeed() * 1024]; 255 | while ((len = bufferedInputStream.read(bytes)) != -1) { 256 | fileOutputStream.write(bytes, 0, len); 257 | Thread.sleep(1000); 258 | } 259 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 260 | if (eTime == 0) eTime = 1; 261 | float pSecond = file.length() / eTime; 262 | fileOutputStream.flush(); 263 | send.send(Dict.transferComplete(file.length(), eTime, pSecond)); 264 | inputStream.close(); 265 | fileOutputStream.close(); 266 | } catch (FileNotFoundException FNFE) { 267 | send.send(Dict.permissionDenied()); 268 | FNFE.printStackTrace(); 269 | } 270 | } else { 271 | try { 272 | FileWriter fileWriter = new FileWriter(file); 273 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 274 | InputStream inputStream = socket.getInputStream(); 275 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 276 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 277 | int len = -1; 278 | long sTime = System.currentTimeMillis(); 279 | char[] chars = new char[speedLimitBind.getUploadSpeed() * 1024]; 280 | while ((len = bufferedReader.read(chars)) != -1) { 281 | bufferedWriter.write(String.valueOf(chars, 0, len).replaceAll("\r\n", "\n")); 282 | Thread.sleep(1000); 283 | } 284 | long eTime = (System.currentTimeMillis() - sTime) / 1000; 285 | if (eTime == 0) eTime = 1; 286 | float pSecond = file.length() / eTime; 287 | bufferedWriter.flush(); 288 | send.send(Dict.transferCompleteInAsciiMode(file.length(), eTime, pSecond)); 289 | bufferedReader.close(); 290 | inputStreamReader.close(); 291 | inputStream.close(); 292 | bufferedWriter.close(); 293 | fileWriter.close(); 294 | } catch (FileNotFoundException FNFE) { 295 | send.send(Dict.permissionDenied()); 296 | FNFE.printStackTrace(); 297 | } 298 | } 299 | } 300 | privateVariable.resetRest(); 301 | } 302 | if (path != null) { 303 | socket.close(); 304 | } else { 305 | kb = bts / 1000; 306 | socket.close(); 307 | long endTime = (System.currentTimeMillis() - startTime) / 1000; 308 | if (endTime == 0) endTime = 1; 309 | float perSecond = kb / endTime; 310 | if (isASCII && listening == null) { 311 | send.send(Dict.transferCompleteInAsciiMode(bts, endTime, perSecond)); 312 | } else { 313 | send.send(Dict.transferComplete(bts, endTime, perSecond)); 314 | } 315 | } 316 | } 317 | } catch (SocketException SE) { 318 | Logger.log(Types.SYS, Levels.ERROR, "Listening stopped."); 319 | } catch (IOException IOE) { 320 | //TODO 321 | IOE.printStackTrace(); 322 | } catch (Exception E) { 323 | E.printStackTrace(); 324 | } finally { 325 | if (pauseListen.isRunning()) { 326 | privateVariable.setTimeoutLock(false); 327 | } 328 | send = null; 329 | privateVariable = null; 330 | pauseListen = null; 331 | socket = null; 332 | listening = null; 333 | file = null; 334 | Logger.log(Types.SYS, Levels.DEBUG, "PORT Closed."); 335 | } 336 | } else { 337 | privateVariable.setInterrupted(true); 338 | } 339 | } 340 | 341 | public void hello(String message) { 342 | listening = message; 343 | } 344 | 345 | public void hello(File file) { 346 | this.file = file; 347 | } 348 | 349 | public void helloSTOR(String path) { 350 | this.path = path; 351 | } 352 | 353 | public void stopSocket() { 354 | try { 355 | socket.shutdownInput(); 356 | socket.shutdownOutput(); 357 | socket.close(); 358 | Logger.log(Types.SYS, Levels.DEBUG, "Socket on " + socket.getLocalSocketAddress() + "stopped."); 359 | } catch (IOException IOE) { 360 | IOE.printStackTrace(); 361 | } catch (NullPointerException NPE) { 362 | Logger.log(Types.SYS, Levels.WARN, "Latest port mode port not connected. Closing forced."); 363 | } 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/pool/handler/HandlerPool.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.pool.handler; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | *Public class to store thread pools.
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-09-19 09:21 12 | **/ 13 | public class HandlerPool { 14 | public static ExecutorService handlerPool = Executors.newCachedThreadPool(); 15 | } 16 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/tool/AutoInputStream.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.tool; 2 | 3 | /** 4 | *AutoInputStream can analyze Chinese encoding from InputStream, and print it out correctly.
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-09-19 09:21 9 | **/ 10 | 11 | import pers.adlered.liteftpd.analyze.PrivateVariable; 12 | import pers.adlered.liteftpd.logger.enums.Levels; 13 | import pers.adlered.liteftpd.logger.Logger; 14 | import pers.adlered.liteftpd.logger.enums.Types; 15 | 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.nio.charset.StandardCharsets; 19 | 20 | public class AutoInputStream { 21 | private InputStream inputStream = null; 22 | private int cacheSize = 0; 23 | private PrivateVariable privateVariable = null; 24 | 25 | public AutoInputStream(InputStream inputStream, int cacheSize, PrivateVariable privateVariable) { 26 | this.inputStream = inputStream; 27 | this.cacheSize = cacheSize; 28 | this.privateVariable = privateVariable; 29 | } 30 | 31 | public String readLineAuto() throws IOException { 32 | byte[] storage = new byte[cacheSize]; 33 | int c2Cursor = 0; 34 | while (true) { 35 | int available = 0; 36 | try { 37 | while (available == 0) { 38 | available = inputStream.available(); 39 | Thread.sleep(5); 40 | } 41 | } catch (IOException IOE) { 42 | Logger.log(Types.SEND, Levels.WARN, "Auto Input Stream stopped."); 43 | break; 44 | } catch (InterruptedException IE) { 45 | } 46 | byte[] cache = new byte[available]; 47 | inputStream.read(cache); 48 | int cursor = 0; 49 | int relativeLength = c2Cursor + cache.length; 50 | if (relativeLength <= cacheSize) { 51 | for (int i = c2Cursor; i < relativeLength; i++) { 52 | storage[i] = cache[cursor]; 53 | ++cursor; 54 | ++c2Cursor; 55 | } 56 | // Check if space exists, break it. 57 | if (new String(storage, StandardCharsets.UTF_8).indexOf("\n") != -1) { 58 | break; 59 | } 60 | } else { 61 | break; 62 | } 63 | } 64 | // Clean wasted space 65 | int storageCursor = 0; 66 | int firstEmptyMark = -1; 67 | boolean marked = false; 68 | for (byte i : storage) { 69 | if (i == 0) { 70 | if (!marked) { 71 | marked = true; 72 | firstEmptyMark = storageCursor; 73 | } 74 | } 75 | ++storageCursor; 76 | } 77 | if (firstEmptyMark == -1) firstEmptyMark = storage.length; 78 | // Init a fit size bytes. 79 | byte[] cleaned = new byte[firstEmptyMark]; 80 | for (int i = 0; i < firstEmptyMark; i++) { 81 | cleaned[i] = storage[i]; 82 | } 83 | String UTF8 = new String(cleaned, StandardCharsets.UTF_8); 84 | String GB2312 = new String(cleaned, "GB2312"); 85 | String charset = CharsetSelector.getCharset(cleaned); 86 | if (!privateVariable.isEncodeLock()) { 87 | privateVariable.setEncode(charset); 88 | if (charset.equals("GB2312")) { 89 | privateVariable.setEncodeLock(true); 90 | } 91 | } 92 | String bestMatch = new String(cleaned, charset); 93 | return bestMatch; 94 | } 95 | 96 | public String readLineInUTF8() throws IOException { 97 | return ""; 98 | } 99 | 100 | public String readLineInGB2312() throws IOException { 101 | return ""; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/tool/CharsetSelector.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.tool; 2 | 3 | import pers.adlered.liteftpd.logger.enums.Levels; 4 | import pers.adlered.liteftpd.logger.Logger; 5 | import pers.adlered.liteftpd.logger.enums.Types; 6 | import pers.adlered.liteftpd.variable.Variable; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.nio.charset.StandardCharsets; 10 | 11 | /** 12 | *Analyze string's encode.
14 | * 15 | * @author : https://github.com/AdlerED 16 | * @date : 2019-09-19 09:21 17 | **/ 18 | public class CharsetSelector { 19 | public static String getCharset(byte[] bytes) { 20 | // return guessEncoding(bytes); 21 | int UTF8ERR = 0; 22 | int GB2312ERR = 0; 23 | String UTF8 = null; 24 | String GB2312 = null; 25 | try { 26 | UTF8 = new String(bytes, StandardCharsets.UTF_8); 27 | GB2312 = new String(bytes, "GB2312"); 28 | } catch (UnsupportedEncodingException UEE) { 29 | // TODO 30 | UEE.printStackTrace(); 31 | } 32 | if (UTF8 != null) { 33 | int fromIndex = 0; 34 | int count = 0; 35 | while (true) { 36 | int index = UTF8.indexOf("�", fromIndex); 37 | if (-1 != index) { 38 | fromIndex = index + 1; 39 | count++; 40 | } else { 41 | break; 42 | } 43 | } 44 | while (true) { 45 | int index = UTF8.indexOf("ţ", fromIndex); 46 | if (-1 != index) { 47 | fromIndex = index + 1; 48 | count++; 49 | } else { 50 | break; 51 | } 52 | } 53 | while (true) { 54 | int index = UTF8.indexOf("Ƥ", fromIndex); 55 | if (-1 != index) { 56 | fromIndex = index + 1; 57 | count++; 58 | } else { 59 | break; 60 | } 61 | } 62 | UTF8ERR = count; 63 | Logger.log(Types.SYS, Levels.DEBUG, "UTF8 " + count); 64 | } 65 | if (GB2312 != null) { 66 | int fromIndex = 0; 67 | int count = 0; 68 | while (true) { 69 | int index = GB2312.indexOf("�", fromIndex); 70 | if (-1 != index) { 71 | fromIndex = index + 1; 72 | count++; 73 | } else { 74 | break; 75 | } 76 | } 77 | GB2312ERR = count; 78 | Logger.log(Types.SYS, Levels.DEBUG, "GB2312 " + count); 79 | } 80 | if (UTF8ERR < GB2312ERR) { 81 | return "UTF-8"; 82 | } else if (UTF8ERR > GB2312ERR) { 83 | return "GB2312"; 84 | } else { 85 | return Variable.defaultEncode; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/tool/ConsoleTable.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.tool; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | *生成控制台表格
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-10-04 18:06 12 | **/ 13 | public class ConsoleTable { 14 | private static int margin = 2; 15 | private ListGreetings for users.
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-09-19 09:21 12 | **/ 13 | public class GoodXX { 14 | public static String getTimeAsWord() { 15 | Date date = new Date(); 16 | SimpleDateFormat df = new SimpleDateFormat("HH"); 17 | String str = df.format(date); 18 | int a = Integer.parseInt(str); 19 | if (a >= 0 && a <= 12) { 20 | return "morning"; 21 | } 22 | if (a > 12 && a <= 13) { 23 | return "noon"; 24 | } 25 | if (a > 13 && a <= 17) { 26 | return "afternoon"; 27 | } 28 | if (a > 17 && a <= 19) { 29 | return "evening"; 30 | } 31 | if (a > 19 && a <= 24) { 32 | return "night"; 33 | } 34 | return ""; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/tool/LocalAddress.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.tool; 2 | 3 | import java.net.Inet4Address; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.SocketException; 7 | import java.util.ArrayList; 8 | import java.util.Enumeration; 9 | import java.util.List; 10 | 11 | /** 12 | *Get IP Address of the server.
14 | * 15 | * @author : https://github.com/AdlerED 16 | * @date : 2019-09-19 09:21 17 | **/ 18 | public class LocalAddress { 19 | public static ListSum random num.
8 | * 9 | * @author : https://github.com/AdlerED 10 | * @date : 2019-09-19 09:21 11 | **/ 12 | public class RandomNum { 13 | public static boolean debugMode = false; //为true 控制台会显示计算过程输出(影响取随机数性能) 14 | 15 | public static int sumIntger(int min, int max, boolean needNegative) { 16 | int result; 17 | Random random = new Random(); 18 | int sumNum = random.nextInt(max - min + 1) + min; 19 | if (needNegative == true) { 20 | int temp = random.nextInt(10) + 1; 21 | Int2String i2s = new Int2String(0); 22 | i2s.setInt(sumNum); 23 | String randomArg = i2s.returnString(); 24 | switch (temp) { 25 | case 1: 26 | if ((randomArg.contains("0")) || (randomArg.contains("9"))) { 27 | randomArg = "-" + randomArg; 28 | break; 29 | } 30 | case 2: 31 | if ((randomArg.contains("1")) || (randomArg.contains("8"))) { 32 | randomArg = "-" + randomArg; 33 | break; 34 | } 35 | case 3: 36 | if ((randomArg.contains("2")) || (randomArg.contains("7"))) { 37 | randomArg = "-" + randomArg; 38 | break; 39 | } 40 | case 4: 41 | if ((randomArg.contains("3")) || (randomArg.contains("6"))) { 42 | randomArg = "-" + randomArg; 43 | break; 44 | } 45 | case 5: 46 | if ((randomArg.contains("4")) || (randomArg.contains("5"))) { 47 | randomArg = "-" + randomArg; 48 | break; 49 | } 50 | } 51 | sumNum = Integer.parseInt(randomArg); 52 | result = sumNum; 53 | return result; 54 | } 55 | return sumNum; 56 | } 57 | 58 | public static double sumDecimal(double min, double max, boolean needNegative) { 59 | double result = 0; 60 | int minInt = (int) min; 61 | if (debugMode == true) { 62 | System.out.println("(最低) 整数位 = " + minInt); 63 | } 64 | String temp = min + ""; 65 | String temp2 = temp.substring(temp.indexOf(".")); 66 | String temp3 = temp2.replace(".", ""); //提取出小数位 67 | if (debugMode == true) { 68 | System.out.println("(最低) 小数位 = " + temp3); 69 | System.out.println("最低小数位长度: " + temp3.length()); 70 | } 71 | int maxInt = (int) max; 72 | if (debugMode == true) { 73 | System.out.println("(最高) 整数位: " + maxInt); 74 | } 75 | String decTemp = max + ""; 76 | String decTemp2 = decTemp.substring(temp.indexOf(".")); 77 | String decTemp3 = decTemp2.replace(".", ""); 78 | if (debugMode == true) { 79 | System.out.println("(最高) 小数位: " + decTemp3); 80 | System.out.println("最高小数位长度: " + decTemp3.length()); 81 | } 82 | // String结果转int 83 | int minDecimalResult; 84 | int maxDecimalResult; 85 | minDecimalResult = Integer.valueOf(temp3).intValue(); 86 | maxDecimalResult = Integer.valueOf(decTemp3).intValue(); 87 | if (debugMode == true) { 88 | System.out.println("转换后小数范围: " + minDecimalResult + " " + maxDecimalResult); 89 | } 90 | // 先生成一个整数位范围内的数字 91 | // 再生成一个小数位范围内的数字 92 | // 最后判断是否符合范围要求, 如果符合 返回 如果不符合 重来 93 | boolean isOk = false; //do while会检查isOk 如果不符合条件(isOk = true)会重来 94 | do { 95 | // 整数数字生成 96 | int getInt = sumIntger(minInt, maxInt, false); 97 | if (debugMode == true) { 98 | System.out.println("整数数字已生成: " + getInt); 99 | } 100 | // 小数数字生成 随机就好 注意小数位数 101 | // 其实不用看最低小数,取0-最高小数就可以了 102 | int getDec = 0; 103 | if (minInt == maxInt) { 104 | if (minDecimalResult < maxDecimalResult) 105 | getDec = sumIntger(minDecimalResult, maxDecimalResult, false); 106 | if (minDecimalResult > maxDecimalResult) 107 | getDec = sumIntger(maxDecimalResult, minDecimalResult, false); 108 | } else { //瞎猫碰上死耗子 109 | if (minDecimalResult < maxDecimalResult) 110 | getDec = sumIntger(0, maxDecimalResult, false); 111 | if (minDecimalResult > maxDecimalResult) 112 | getDec = sumIntger(0, minDecimalResult, false); 113 | } 114 | if (debugMode == true) { 115 | System.out.println("小数数字已生成: " + getDec); 116 | } 117 | // 开始组合 118 | String spell = getInt + "." + getDec; 119 | double getSpell = Double.valueOf(spell); 120 | if (debugMode == true) { 121 | System.out.println("随机数已生成: " + getSpell); 122 | } 123 | // if (getDec >= minDecimalResult && getDec <= maxDecimalResult) { 124 | if (minInt != maxInt) { //算法不同 不相为谋 125 | if (getInt == minInt && getDec >= minDecimalResult) { 126 | isOk = true; 127 | } else if (getInt == maxInt && getDec <= maxDecimalResult) { 128 | isOk = true; 129 | } else if (getInt != minInt && getInt != maxInt) { 130 | isOk = true; 131 | } 132 | } else { 133 | if (getDec >= minDecimalResult && getDec <= maxDecimalResult) { 134 | isOk = true; 135 | } 136 | } 137 | // 如果整数不是最小也不是最大 那小数位就可以随便生成了 138 | if (isOk == false) { 139 | if (debugMode == true) { 140 | System.out.println("随机生成的随机数不符合要求,自动重新生成..."); 141 | } 142 | } else { 143 | result = getSpell; 144 | } 145 | } while (isOk == false); 146 | // 利用判断 看看组合后的小数是否在设定的范围之内(有点影响性能...不过可以实现) 147 | if (needNegative == true) { 148 | Random random = new Random(); 149 | int tempR = random.nextInt(10) + 1; 150 | Double2String d2s = new Double2String(result); 151 | String randomArg = d2s.returnString(); 152 | switch (tempR) { 153 | case 1: 154 | if ((randomArg.contains("0")) || (randomArg.contains("9"))) { 155 | randomArg = "-" + randomArg; 156 | break; 157 | } 158 | case 2: 159 | if ((randomArg.contains("1")) || (randomArg.contains("8"))) { 160 | randomArg = "-" + randomArg; 161 | break; 162 | } 163 | case 3: 164 | if ((randomArg.contains("2")) || (randomArg.contains("7"))) { 165 | randomArg = "-" + randomArg; 166 | break; 167 | } 168 | case 4: 169 | if ((randomArg.contains("3")) || (randomArg.contains("6"))) { 170 | randomArg = "-" + randomArg; 171 | break; 172 | } 173 | case 5: 174 | if ((randomArg.contains("4")) || (randomArg.contains("5"))) { 175 | randomArg = "-" + randomArg; 176 | break; 177 | } 178 | } 179 | double getRes = Double.valueOf(randomArg); 180 | result = getRes; 181 | } 182 | if (debugMode == true) { 183 | System.out.println("最终取数: " + result); 184 | } 185 | return result; 186 | } 187 | 188 | static class Int2String { 189 | String ArgNum = ""; 190 | 191 | public Int2String(int RecivedNum) { 192 | ArgNum = RecivedNum + ""; 193 | } 194 | 195 | String returnString() { 196 | return ArgNum; 197 | } 198 | 199 | void setInt(int RecivedNum) { 200 | ArgNum = RecivedNum + ""; 201 | } 202 | } 203 | 204 | static class Double2String { 205 | String ArgNum = ""; 206 | 207 | public Double2String(double RecivedNum) { 208 | ArgNum = RecivedNum + ""; 209 | } 210 | 211 | String returnString() { 212 | return ArgNum; 213 | } 214 | 215 | void setDouble(double RecivedNum) { 216 | ArgNum = RecivedNum + ""; 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/tool/Status.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.tool; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.MemoryMXBean; 5 | import java.lang.management.MemoryUsage; 6 | 7 | /** 8 | *Get information of the server.
10 | * 11 | * @author : https://github.com/AdlerED 12 | * @date : 2019-09-19 09:21 13 | **/ 14 | public class Status { 15 | public static String memoryUsed() { 16 | MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); 17 | MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage(); 18 | return (memoryUsage.getUsed() / 1048576) + "MB"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/User.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user; 2 | 3 | import pers.adlered.liteftpd.variable.Variable; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | *Store users.
11 | * 12 | * @author : https://github.com/AdlerED 13 | * @date : 2019-09-19 09:21 14 | **/ 15 | public class User { 16 | private static Map用户信息
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-10-04 19:16 9 | **/ 10 | public class UserProps { 11 | private String password; 12 | private String permission; 13 | private String permitDir; 14 | private String defaultDir; 15 | 16 | public String getPassword() { 17 | return password; 18 | } 19 | 20 | public void setPassword(String password) { 21 | this.password = password; 22 | } 23 | 24 | public String getPermission() { 25 | return permission; 26 | } 27 | 28 | public void setPermission(String permission) { 29 | this.permission = permission; 30 | } 31 | 32 | public String getPermitDir() { 33 | return permitDir; 34 | } 35 | 36 | public void setPermitDir(String permitDir) { 37 | this.permitDir = permitDir; 38 | } 39 | 40 | public String getDefaultDir() { 41 | return defaultDir; 42 | } 43 | 44 | public void setDefaultDir(String defaultDir) { 45 | this.defaultDir = defaultDir; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/info/OnlineInfo.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.info; 2 | 3 | import pers.adlered.liteftpd.user.info.bind.UserInfoBind; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | *存储所有在线用户详细信息的数组
11 | * 12 | * @author : https://github.com/AdlerED 13 | * @date : 2019-10-05 21:47 14 | **/ 15 | public class OnlineInfo { 16 | public static final List存储在线用户详细信息
9 | * 10 | * @author : https://github.com/AdlerED 11 | * @date : 2019-10-05 21:41 12 | **/ 13 | public class UserInfoBind { 14 | private IpLimitBind ipLimitBind; 15 | private UserLimitBind userLimitBind; 16 | 17 | public UserInfoBind(IpLimitBind ipLimitBind, UserLimitBind userLimitBind) { 18 | this.ipLimitBind = ipLimitBind; 19 | this.userLimitBind = userLimitBind; 20 | } 21 | 22 | public IpLimitBind getIpLimitBind() { 23 | return ipLimitBind; 24 | } 25 | 26 | public void setIpLimitBind(IpLimitBind ipLimitBind) { 27 | this.ipLimitBind = ipLimitBind; 28 | } 29 | 30 | public UserLimitBind getUserLimitBind() { 31 | return userLimitBind; 32 | } 33 | 34 | public void setUserLimitBind(UserLimitBind userLimitBind) { 35 | this.userLimitBind = userLimitBind; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/status/Online.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.status; 2 | 3 | import pers.adlered.liteftpd.user.status.bind.IpLimitBind; 4 | import pers.adlered.liteftpd.user.status.bind.UserLimitBind; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | *记录在线的用户信息,用于限制连接数和读取信息。
12 | * 13 | * @author : https://github.com/AdlerED 14 | * @date : 2019-10-05 14:51 15 | **/ 16 | public class Online { 17 | // 存储指定规则的在线IP数量 18 | public static final ListA bind of server/client IP Address.
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-09-19 09:21 9 | **/ 10 | public class IPAddressBind { 11 | private String IPADD; 12 | private String SRVIPADD; 13 | 14 | public IPAddressBind(String IPADD, String SRVIPADD) { 15 | this.IPADD = IPADD; 16 | this.SRVIPADD = SRVIPADD; 17 | } 18 | 19 | public String getIPADD() { 20 | return IPADD; 21 | } 22 | 23 | public void setIPADD(String IPADD) { 24 | this.IPADD = IPADD; 25 | } 26 | 27 | public String getSRVIPADD() { 28 | return SRVIPADD; 29 | } 30 | 31 | public void setSRVIPADD(String SRVIPADD) { 32 | this.SRVIPADD = SRVIPADD; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/status/bind/IpLimitBind.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.status.bind; 2 | 3 | /** 4 | *IP地址限制
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-10-05 15:14 9 | **/ 10 | public class IpLimitBind { 11 | String ip; 12 | String rule; 13 | 14 | public IpLimitBind(String ip, String rule) { 15 | this.ip = ip; 16 | this.rule = rule; 17 | } 18 | 19 | public String getIp() { 20 | return ip; 21 | } 22 | 23 | public void setIp(String ip) { 24 | this.ip = ip; 25 | } 26 | 27 | public String getRule() { 28 | return rule; 29 | } 30 | 31 | public void setRule(String rule) { 32 | this.rule = rule; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/status/bind/SpeedLimitBind.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.status.bind; 2 | 3 | /** 4 | *限速Bind
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-10-12 16:12 9 | **/ 10 | public class SpeedLimitBind { 11 | private int uploadSpeed; 12 | private int downloadSpeed; 13 | 14 | public SpeedLimitBind(int uploadSpeed, int downloadSpeed) { 15 | this.uploadSpeed = uploadSpeed; 16 | this.downloadSpeed = downloadSpeed; 17 | } 18 | 19 | public int getUploadSpeed() { 20 | return uploadSpeed; 21 | } 22 | 23 | public void setUploadSpeed(int uploadSpeed) { 24 | this.uploadSpeed = uploadSpeed; 25 | } 26 | 27 | public int getDownloadSpeed() { 28 | return downloadSpeed; 29 | } 30 | 31 | public void setDownloadSpeed(int downloadSpeed) { 32 | this.downloadSpeed = downloadSpeed; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/status/bind/UserLimitBind.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.status.bind; 2 | 3 | /** 4 | *用户限制
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-10-05 21:02 9 | **/ 10 | public class UserLimitBind { 11 | String username; 12 | String rule; 13 | 14 | public UserLimitBind(String username, String rule) { 15 | this.username = username; 16 | this.rule = rule; 17 | } 18 | 19 | public String getUsername() { 20 | return username; 21 | } 22 | 23 | public void setUsername(String username) { 24 | this.username = username; 25 | } 26 | 27 | public String getRule() { 28 | return rule; 29 | } 30 | 31 | public void setRule(String rule) { 32 | this.rule = rule; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/user/verify/OnlineRules.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.user.verify; 2 | 3 | import pers.adlered.liteftpd.user.status.bind.IpLimitBind; 4 | import pers.adlered.liteftpd.user.status.Online; 5 | import pers.adlered.liteftpd.user.status.bind.SpeedLimitBind; 6 | import pers.adlered.liteftpd.user.status.bind.UserLimitBind; 7 | import pers.adlered.liteftpd.variable.Variable; 8 | 9 | /** 10 | *检测连接数限制,返回True或者False决定是否接受连接。
12 | * 13 | * @author : https://github.com/AdlerED 14 | * @date : 2019-10-05 14:49 15 | **/ 16 | public class OnlineRules { 17 | /** 18 | * 检查IP地址是否可以登录 19 | * 20 | * @param ipAddress 21 | * @return 返回生成后的IP Bind,用于进一步获取登录用户信息 22 | */ 23 | public static IpLimitBind checkIpAddress(String ipAddress) { 24 | boolean onList = false; 25 | String onListRule = ""; 26 | int onListLimit = -1; 27 | String[] ipRules = Variable.ipOnlineLimit.split(";"); 28 | String[] ip = ipAddress.split("\\."); 29 | for (int i = 0; i < ipRules.length; i += 2) { 30 | if (ipRules[i].equals("0.0.0.0")) { 31 | onList = true; 32 | onListRule = ipRules[i]; 33 | onListLimit = Integer.parseInt(ipRules[i + 1]); 34 | } 35 | String[] ruleIp = ipRules[i].split("\\."); 36 | // 首先,第一位需要相等 37 | if (ruleIp[0].equals(ip[0]) || ruleIp[0].toLowerCase().equals("x")) { 38 | if (ruleIp[1].equals(ip[1]) || ruleIp[1].toLowerCase().equals("x")) { 39 | if (ruleIp[2].equals(ip[2]) || ruleIp[2].toLowerCase().equals("x")) { 40 | if (ruleIp[3].equals(ip[3]) || ruleIp[3].toLowerCase().equals("x")) { 41 | onList = true; 42 | onListRule = ipRules[i]; 43 | onListLimit = Integer.parseInt(ipRules[i + 1]); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | if (onList) { 50 | if (onListLimit == 0) { 51 | return new IpLimitBind(null, null); 52 | } else { 53 | int count = 0; 54 | for (IpLimitBind ipRule : Online.ipRuleOnline) { 55 | if (ipRule.getRule().equals(onListRule)) { 56 | ++count; 57 | } 58 | } 59 | if (count < onListLimit) { 60 | IpLimitBind ipLimitBind = new IpLimitBind(ipAddress, onListRule); 61 | Online.ipRuleOnline.add(ipLimitBind); 62 | return ipLimitBind; 63 | } else { 64 | return new IpLimitBind(null, null); 65 | } 66 | } 67 | } else { 68 | IpLimitBind ipLimitBind = new IpLimitBind(ipAddress, onListRule); 69 | Online.ipRuleOnline.add(ipLimitBind); 70 | return ipLimitBind; 71 | } 72 | } 73 | 74 | /** 75 | * 检查用户名是否达到了上限 76 | * 77 | * @param username 78 | * @return 禁止登录返回null 79 | */ 80 | public static UserLimitBind checkUsername(String username) { 81 | boolean onList = false; 82 | String onListRule = ""; 83 | int onListLimit = -1; 84 | String[] userRules = Variable.userOnlineLimit.split(";"); 85 | // 先检测,再执行,通配符优先级最高 86 | for (int i = 0; i < userRules.length; i += 2) { 87 | if (userRules[i].equals("%")) { 88 | onList = true; 89 | onListRule = userRules[i]; 90 | onListLimit = Integer.parseInt(userRules[i + 1]); 91 | } 92 | if (userRules[i].equals(username)) { 93 | onList = true; 94 | onListRule = userRules[i]; 95 | onListLimit = Integer.parseInt(userRules[i + 1]); 96 | } 97 | } 98 | if (onList) { 99 | if (onListLimit == 0) { 100 | return new UserLimitBind(null, null); 101 | } else { 102 | int count = 0; 103 | for (UserLimitBind userRule : Online.userRuleOnline) { 104 | if (userRule.getRule().equals(onListRule)) { 105 | ++count; 106 | } 107 | } 108 | if (count < onListLimit) { 109 | UserLimitBind userLimitBind = new UserLimitBind(username, onListRule); 110 | Online.userRuleOnline.add(userLimitBind); 111 | return userLimitBind; 112 | } else { 113 | return new UserLimitBind(null, null); 114 | } 115 | } 116 | } else { 117 | UserLimitBind userLimitBind = new UserLimitBind(username, onListRule); 118 | Online.userRuleOnline.add(userLimitBind); 119 | return userLimitBind; 120 | } 121 | } 122 | 123 | public static SpeedLimitBind getSpeedLimit(String username) { 124 | String[] speedRules = Variable.speedLimit.split(";"); 125 | for (int i = 0; i < speedRules.length; i += 3) { 126 | String currentUser = speedRules[i]; 127 | if (currentUser.equals(username)) { 128 | int uploadSpeed; 129 | if (speedRules[i + 1].isEmpty() || speedRules[i + 1].equals("0")) { 130 | uploadSpeed = 0; 131 | } else { 132 | uploadSpeed = Integer.parseInt(speedRules[i + 1]); 133 | } 134 | int downloadSpeed; 135 | if (speedRules[i + 2].isEmpty() || speedRules[i + 2].equals("0")) { 136 | downloadSpeed = 0; 137 | } else { 138 | downloadSpeed = Integer.parseInt(speedRules[i + 2]); 139 | } 140 | return new SpeedLimitBind(uploadSpeed, downloadSpeed); 141 | } 142 | } 143 | return new SpeedLimitBind(0, 0); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/variable/OnlineUserController.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.variable; 2 | 3 | import pers.adlered.liteftpd.logger.enums.Levels; 4 | import pers.adlered.liteftpd.logger.Logger; 5 | import pers.adlered.liteftpd.logger.enums.Types; 6 | import pers.adlered.liteftpd.user.status.Online; 7 | 8 | /** 9 | *Variable bean.
11 | * 12 | * @author : https://github.com/AdlerED 13 | * @date : 2019-09-19 09:21 14 | **/ 15 | public class OnlineUserController { 16 | public static void printOnline() { 17 | int ipSize = Online.ipRuleOnline.size(); 18 | int userSize = Online.userRuleOnline.size(); 19 | Logger.log(Types.SYS, Levels.INFO, "Online Users: " + userSize + " Connections: " + ipSize); 20 | } 21 | 22 | public static void reduceOnline(String ipAddress, String username) { ; 23 | for (int i = 0; i < Online.ipRuleOnline.size(); i++) { 24 | if (Online.ipRuleOnline.get(i).getIp().equals(ipAddress)) { 25 | Online.ipRuleOnline.remove(i); 26 | break; 27 | } 28 | } 29 | for (int i = 0; i < Online.userRuleOnline.size(); i++) { 30 | if (Online.userRuleOnline.get(i).getUsername().equals(username)) { 31 | Online.userRuleOnline.remove(i); 32 | break; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/variable/Variable.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.variable; 2 | 3 | /** 4 | *User interface settings.
6 | * 7 | * @author : https://github.com/AdlerED 8 | * @date : 2019-09-19 09:21 9 | **/ 10 | public class Variable { 11 | public static String user = "1;anonymous;;r;2;admin;123456;r"; 12 | public static String ipOnlineLimit = ""; 13 | public static String userOnlineLimit = ""; 14 | public static String speedLimit=""; 15 | public static int debugLevel = 4; 16 | public static int online = 0; 17 | public static long maxUserLimit = 100; 18 | public static int timeout = 100; 19 | public static int maxTimeout = 21600; 20 | public static boolean smartEncode = true; 21 | public static String defaultEncode = "UTF-8"; 22 | public static int port = 21; 23 | public static String welcomeMessage = ""; 24 | public static int minPort = 10240; 25 | public static int maxPort = 20480; 26 | } 27 | -------------------------------------------------------------------------------- /src/pers/adlered/liteftpd/wizard/config/Prop.java: -------------------------------------------------------------------------------- 1 | package pers.adlered.liteftpd.wizard.config; 2 | 3 | import pers.adlered.liteftpd.logger.enums.Levels; 4 | import pers.adlered.liteftpd.logger.Logger; 5 | import pers.adlered.liteftpd.logger.enums.Types; 6 | import pers.adlered.liteftpd.variable.Variable; 7 | 8 | import java.io.*; 9 | import java.lang.reflect.Field; 10 | import java.util.*; 11 | 12 | /** 13 | *配置文件读写操作类
15 | * 16 | * @author : https://github.com/AdlerED 17 | * @date : 2019-10-03 23:45 18 | **/ 19 | public class Prop { 20 | private static Properties properties = new Properties(); 21 | 22 | private static Prop prop = null; 23 | 24 | private Prop() { 25 | try { 26 | BufferedReader bufferedReader = new BufferedReader(new FileReader("config.prop")); 27 | properties.load(bufferedReader); 28 | Logger.log(Types.SYS, Levels.INFO, "Profile \"config.prop\" loaded successfully."); 29 | } catch (FileNotFoundException FNFE) { 30 | Logger.log(Types.SYS, Levels.WARN, "Cannot found properties file \"config.prop\" at the root path, re-generating default..."); 31 | try { 32 | File file = new File("config.prop"); 33 | file.createNewFile(); 34 | // Set default props 35 | addAnnotation("# ================================================================================================") 36 | .addAnnotation("# ================================================================================================") 37 | .addAnnotation("# >>> LiteFTPD-UNIX Configure File") 38 | .addAnnotation("# ") 39 | .addAnnotation("# >> debugLevel") 40 | .addAnnotation("# ") 41 | .addAnnotation("# Too high level can affect performance!") 42 | .addAnnotation("# 0: NONE;") 43 | .addAnnotation("# 1: INFO;") 44 | .addAnnotation("# 2: WARN && INFO;") 45 | .addAnnotation("# 3: ERROR && WARN && INFO;") 46 | .addAnnotation("# 4: DEBUG && ERROR && WARN && INFO.") 47 | .addAnnotation("# ") 48 | .addAnnotation("# Debug等级,调整过高可能会影响性能!") 49 | .addAnnotation("# 0:无输出;") 50 | .addAnnotation("# 1:输出 INFO 信息;") 51 | .addAnnotation("# 2:输出 WARN 及 INFO 信息;") 52 | .addAnnotation("# 3:输出 ERROR 、 WARN 及 INFO 信息;") 53 | .addAnnotation("# 4:输出 DEBUG 、 ERROR 、 WARN 及 INFO 信息。") 54 | .addAnnotation("# ") 55 | .addAnnotation("# >> maxUserLimit") 56 | .addAnnotation("# ") 57 | .addAnnotation("# Set to 0, will be ignore the limit. Too small value may make multi-thread ftp client not working.") 58 | .addAnnotation("# ") 59 | .addAnnotation("# 同时连接数限制。设置至0代表不限制。过小的值可能会导致多线程的FTP客户端无法正常工作。") 60 | .addAnnotation("# ") 61 | .addAnnotation("# >> timeout") 62 | .addAnnotation("# ") 63 | .addAnnotation("# Timeout in second.") 64 | .addAnnotation("# ") 65 | .addAnnotation("# 连接空闲超时时间。") 66 | .addAnnotation("# ") 67 | .addAnnotation("# >> maxTimeout") 68 | .addAnnotation("# ") 69 | .addAnnotation("# On mode timeout when client is on passive or initiative mode. (default: 21600 sec = 6 hrs)") 70 | .addAnnotation("# ") 71 | .addAnnotation("# 传输时最高的超时时间。(默认:21600秒 = 6小时)") 72 | .addAnnotation("# ") 73 | .addAnnotation("# >> smartEncode") 74 | .addAnnotation("# ") 75 | .addAnnotation("# Smart choose transmission encode.") 76 | .addAnnotation("# ") 77 | .addAnnotation("# 开启后,LiteFTPD会自动检测编码,以兼容各种系统的FTP客户端。") 78 | .addAnnotation("# ") 79 | .addAnnotation("# >> defaultEncode") 80 | .addAnnotation("# ") 81 | .addAnnotation("# Set the default translating encode. Unix is UTF-8, Windows is GB2312.") 82 | .addAnnotation("# ") 83 | .addAnnotation("# 设置默认的传输编码。 Unix系统为UTF-8,Windows为GB2312。") 84 | .addAnnotation("# ") 85 | .addAnnotation("# >> port") 86 | .addAnnotation("# ") 87 | .addAnnotation("# FTP Server listening tcp port.") 88 | .addAnnotation("# ") 89 | .addAnnotation("# FTP服务监听的TCP端口号。") 90 | .addAnnotation("# ") 91 | .addAnnotation("# >> welcomeMessage") 92 | .addAnnotation("# ") 93 | .addAnnotation("# Customize welcome message when user visited.") 94 | .addAnnotation("# ") 95 | .addAnnotation("# 自定义用户连接时的欢迎信息。") 96 | .addAnnotation("# ") 97 | .addAnnotation("# >> minPort && maxPort") 98 | .addAnnotation("# ") 99 | .addAnnotation("# Appoint passive mode port range.") 100 | .addAnnotation("# Recommend 100+ ports in the range to make sure generation have high-performance!") 101 | .addAnnotation("# ") 102 | .addAnnotation("# 自定义被动模式使用的端口范围。") 103 | .addAnnotation("# 建议在范围中有100个端口以上,以确保FTP服务端的性能。") 104 | .addAnnotation("# ") 105 | .addAnnotation("# >> user") 106 | .addAnnotation("# ") 107 | .addAnnotation("# Multi users. Format:") 108 | .addAnnotation("# user=[username];[password];[permission];[permitDir];[defaultDir]; ...") 109 | .addAnnotation("# username: User's login name.") 110 | .addAnnotation("# password: User's password.") 111 | .addAnnotation("# permission:") 112 | .addAnnotation("# r = read") 113 | .addAnnotation("# w = write") 114 | .addAnnotation("# d = delete") 115 | .addAnnotation("# c = create") 116 | .addAnnotation("# m = move") 117 | .addAnnotation("# Example: rw means read and write permission.") 118 | .addAnnotation("# permitDir: Set dir that user can access.") 119 | .addAnnotation("# Example: \"/\" means user can access the hole disk; \"/home\" means user can access folder/subFolder/files under \"/home\" directory.") 120 | .addAnnotation("# defaultDir: The default dir will be re-directed when user logged.") 121 | .addAnnotation("# ") 122 | .addAnnotation("# 多用户管理。格式:") 123 | .addAnnotation("# user=[用户名];[密码];[权限];[允许访问的目录];[登录时的默认目录]; ...") 124 | .addAnnotation("# 权限:") 125 | .addAnnotation("# r = 读") 126 | .addAnnotation("# w = 写") 127 | .addAnnotation("# d = 删除") 128 | .addAnnotation("# c = 创建") 129 | .addAnnotation("# m = 移动") 130 | .addAnnotation("# 举例:rw 代表读和写的权限。") 131 | .addAnnotation("# 允许访问的目录:设置用户可以访问的目录。") 132 | .addAnnotation("# 举例:“/”代表用户可以访问整个硬盘;“/home”代表用户可以访问在“/home”目录下的所有子目录、目录和文件。") 133 | .addAnnotation("# 登录时的默认目录:登录成功后,用户所在的默认目录。") 134 | .addAnnotation("# ") 135 | .addAnnotation("# >> ipOnlineLimit") 136 | .addAnnotation("# ") 137 | .addAnnotation("# Max connections limit for specify IP Address.") 138 | .addAnnotation("# ipOnlineLimit=[IP];[Limit];[IP];[Limit]; ...") 139 | .addAnnotation("# If you defined IP Address as \"0.0.0.0\", priority will be given to limiting the number of connections per IP address to a specified number (Except for IP Address that have been set up separately).") 140 | .addAnnotation("# \"x\" means \"All\". If you defined \"192.168.x.x\", that connections from range \"192.168.0-255.0-255\" all will be refused.") 141 | .addAnnotation("# BlackList for Ip Address? Set limit to \"0\"!") 142 | .addAnnotation("# !!! Please note! The higher the configuration, the lower the weight of the connection limit (meaning that the more forward, the less likely it is to match). It is recommended to write the configuration of the specified IP at the end, and write the IP configuration using the wildcard in the front. !!!") 143 | .addAnnotation("# For example, =127.0.0.1; 1; 0.0.0.0; 100; When 127.0.0.1 is connected to the server, the maximum number of simultaneous connections allowed is 100! The configuration should be modified to =0.0.0.0;100;127.0.0.1;1;") 144 | .addAnnotation("# ") 145 | .addAnnotation("# 限制指定IP地址的最大同时连接数。") 146 | .addAnnotation("# ipOnlineLimit=[IP地址];[最大连接数];[IP地址];[最大连接数]; ...") 147 | .addAnnotation("# 如果你将IP地址定义为“0.0.0.0”,服务端将把最大连接数规则应用到所有的IP地址中(除非指定IP地址也被单独定义了)。") 148 | .addAnnotation("# “x”代表“所有”。如果你定义为“192.168.x.x”,那么来自“192.168.0-255.0-255”范围的所有IP地址都将受到该规则的限制。") 149 | .addAnnotation("# 想将指定IP地址拉黑?把最大连接数限制为“0”!") 150 | .addAnnotation("# !!! 请注意!配置越往前,连接数限制的权重越低(意味着越往前,匹配到的可能性越小)。建议将指定IP的配置写在最后面,将使用通配符的IP配置写在前面。 !!!") 151 | .addAnnotation("# 例如 =127.0.0.1;1;0.0.0.0;100; 当127.0.0.1连接服务端时,最终获取到允许同时的连接数最大为100!应将配置修改为 =0.0.0.0;100;127.0.0.1;1;") 152 | .addAnnotation("# ") 153 | .addAnnotation("# >> userOnlineLimit") 154 | .addAnnotation("# ") 155 | .addAnnotation("# Max connections limit for specify User.") 156 | .addAnnotation("# userOnlineLimit=[username];[Limit];[username];[Limit]; ...") 157 | .addAnnotation("# If you defined User as \"%\", priority will be given to limiting the number of connections per User to a specified number (Except for users that have been set up separately).") 158 | .addAnnotation("# BlackList for User? Set limit to \"0\"!") 159 | .addAnnotation("# !!! Please note! The higher the configuration, the lower the weight of the connection limit (meaning that the more forward, the less likely it is to match). It is recommended to write the configuration of the specified user to the end, and write the user configuration using the wildcard to the front. !!!") 160 | .addAnnotation("# For example, =admin;1;%;100; When logging in to the user admin, the maximum number of connections allowed to log in at the same time is 100! The configuration should be modified to =%;100;admin;1;") 161 | .addAnnotation("# ") 162 | .addAnnotation("# 限制指定用户的最大同时连接数。") 163 | .addAnnotation("# userOnlineLimit=[用户名];[最大连接数];[用户名];[最大连接数]; ...") 164 | .addAnnotation("# 如果你将用户名定义为“%”,服务端讲把最大连接数规则应用到所有的用户中(除非指定用户也被单独定义了)。") 165 | .addAnnotation("# 想将指定用户拉黑?把最大连接数限制为“0”!") 166 | .addAnnotation("# !!! 请注意!配置越往前,连接数限制的权重越低(意味着越往前,匹配到的可能性越小)。建议将指定用户的配置写在最后面,将使用通配符的用户配置写在前面。 !!!") 167 | .addAnnotation("# 例如 =admin;1;%;100; 当登录用户admin时,最终获取到允许同时登录的连接数最大为100!应将配置修改为 =%;100;admin;1;") 168 | .addAnnotation("# ") 169 | .addAnnotation("# >> speedLimit") 170 | .addAnnotation("# ") 171 | .addAnnotation("# Limit user's upload & download speed. There is no limit") 172 | .addAnnotation("# format: speedLimit=[username];[upload(kb/s)];[download(kb/s)]; ...") 173 | .addAnnotation("# ") 174 | .addAnnotation("# 限制用户的上传和下载速度。数值为0或不填时不限制。") 175 | .addAnnotation("# 格式:speedList=[用户名];[上传速度(kb/秒)];[下载速度(kb/秒)]; ...") 176 | .addAnnotation("# ") 177 | .addAnnotation("# ================================================================================================") 178 | .addAnnotation("# = ↓ CONFIG ↓ =") 179 | .addAnnotation("# ================================================================================================") 180 | .addAnnotation("# "); 181 | addProperty("user", "anonymous;;r;/;/;admin;123456;r;/;/root;") 182 | .addProperty("ipOnlineLimit", "0.0.0.0;100;127.x.x.x;100;192.168.1.x;100;") 183 | .addProperty("userOnlineLimit", "%;100;anonymous;100;admin;100;") 184 | .addProperty("speedLimit", "anonymous;0;10240;admin;;20480;") 185 | .addProperty("debugLevel", "3") 186 | .addProperty("maxUserLimit", "100") 187 | .addProperty("timeout", "100") 188 | .addProperty("maxTimeout", "21600") 189 | .addProperty("smartEncode", "true") 190 | .addProperty("defaultEncode", "UTF-8") 191 | .addProperty("port", "21") 192 | .addProperty("welcomeMessage", "オレは ルフィ、海賊王になる男だ") 193 | .addProperty("minPort", "10240") 194 | .addProperty("maxPort", "20480"); 195 | BufferedReader bufferedReader = new BufferedReader(new FileReader("config.prop")); 196 | properties.load(bufferedReader); 197 | } catch (IOException IOE) { 198 | IOE.printStackTrace(); 199 | } 200 | } catch (IOException IOE) { 201 | IOE.printStackTrace(); 202 | } 203 | // 反射并应用配置 204 | try { 205 | Class clazz = Variable.class; 206 | Set