1 18 package net.sf.drftpd.master.command.plugins; 19 20 import java.io.FileNotFoundException ; 21 import java.io.FileReader ; 22 import java.io.IOException ; 23 import java.util.HashMap ; 24 import java.util.Hashtable ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.StringTokenizer ; 29 30 import net.sf.drftpd.Bytes; 31 import net.sf.drftpd.FileExistsException; 32 import net.sf.drftpd.Nukee; 33 import net.sf.drftpd.ObjectNotFoundException; 34 import net.sf.drftpd.event.NukeEvent; 35 import net.sf.drftpd.master.BaseFtpConnection; 36 import net.sf.drftpd.master.FtpReply; 37 import net.sf.drftpd.master.command.CommandManager; 38 import net.sf.drftpd.master.command.CommandManagerFactory; 39 import net.sf.drftpd.master.queues.NukeLog; 40 import net.sf.drftpd.master.usermanager.AbstractUser; 41 import net.sf.drftpd.master.usermanager.NoSuchUserException; 42 import net.sf.drftpd.master.usermanager.User; 43 import net.sf.drftpd.master.usermanager.UserFileException; 44 import net.sf.drftpd.remotefile.LinkedRemoteFileInterface; 45 46 import org.apache.log4j.Level; 47 import org.apache.log4j.Logger; 48 import org.drftpd.commands.CommandHandler; 49 import org.drftpd.commands.CommandHandlerFactory; 50 import org.drftpd.commands.UnhandledCommandException; 51 import org.jdom.Document; 52 import org.jdom.Element; 53 import org.jdom.input.SAXBuilder; 54 55 62 public class Nuke implements CommandHandlerFactory, CommandHandler { 63 64 private static final Logger logger = Logger.getLogger(Nuke.class); 65 66 public static long calculateNukedAmount( 67 long size, 68 float ratio, 69 int multiplier) { 70 return (long) (size * ratio + size * (multiplier - 1)); 71 } 72 73 private static void nukeRemoveCredits( 74 LinkedRemoteFileInterface nukeDir, 75 Hashtable nukees) { 76 for (Iterator iter = nukeDir.getFiles().iterator(); iter.hasNext();) { 77 LinkedRemoteFileInterface file = 78 (LinkedRemoteFileInterface) iter.next(); 79 if (file.isDirectory()) { 80 nukeRemoveCredits(file, nukees); 81 } 82 if (file.isFile()) { 83 String owner = file.getUsername(); 84 Long total = (Long ) nukees.get(owner); 85 if (total == null) 86 total = new Long (0); 87 total = new Long (total.longValue() + file.length()); 88 nukees.put(owner, total); 89 } 90 } 91 } 92 private NukeLog _nukelog; 93 public Nuke() { 94 } 95 96 119 private FtpReply doSITE_NUKE(BaseFtpConnection conn) { 120 if (!conn.getUserNull().isNuker()) 121 return FtpReply.RESPONSE_530_ACCESS_DENIED; 122 123 if (!conn.getRequest().hasArgument()) { 124 return new FtpReply(501, conn.jprintf(Nuke.class, "nuke.usage")); 125 } 126 127 StringTokenizer st = 128 new StringTokenizer (conn.getRequest().getArgument(), " "); 129 130 if (!st.hasMoreTokens()) { 131 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 132 } 133 134 int multiplier; 135 LinkedRemoteFileInterface nukeDir; 136 String nukeDirName; 137 try { 138 nukeDirName = st.nextToken(); 139 nukeDir = conn.getCurrentDirectory().getFile(nukeDirName); 140 } catch (FileNotFoundException e) { 141 FtpReply response = new FtpReply(550, e.getMessage()); 142 return response; 143 } 144 if (!nukeDir.isDirectory()) { 145 FtpReply response = 146 new FtpReply(550, nukeDirName + ": not a directory"); 147 return response; 148 } 149 String nukeDirPath = nukeDir.getPath(); 150 151 if (!st.hasMoreTokens()) { 152 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 153 } 154 155 try { 156 multiplier = Integer.parseInt(st.nextToken()); 157 } catch (NumberFormatException ex) { 158 logger.warn("", ex); 159 return new FtpReply(501, "Invalid multiplier: " + ex.getMessage()); 160 } 161 162 String reason; 163 if (st.hasMoreTokens()) { 164 reason = st.nextToken("").trim(); 165 } else { 166 reason = ""; 167 } 168 Hashtable nukees = new Hashtable (); 170 nukeRemoveCredits(nukeDir, nukees); 171 172 FtpReply response = new FtpReply(200, "NUKE suceeded"); 173 174 HashMap nukees2 = new HashMap (nukees.size()); 176 for (Iterator iter = nukees.keySet().iterator(); iter.hasNext();) { 177 178 String username = (String ) iter.next(); 179 User user; 180 try { 181 user = 182 conn.getConnectionManager().getUserManager().getUserByName( 183 username); 184 } catch (NoSuchUserException e1) { 185 response.addComment( 186 "Cannot remove credits from " 187 + username 188 + ": " 189 + e1.getMessage()); 190 logger.warn("", e1); 191 user = null; 192 } catch (UserFileException e1) { 193 response.addComment( 194 "Cannot read user data for " 195 + username 196 + ": " 197 + e1.getMessage()); 198 logger.warn("", e1); 199 response.setMessage("NUKE failed"); 200 return response; 201 } 202 if (user == null) { 204 Long add = (Long ) nukees2.get(null); 205 if (add == null) { 206 add = new Long (0); 207 } 208 nukees2.put( 209 user, 210 new Long ( 211 add.longValue() 212 + ((Long ) nukees.get(username)).longValue())); 213 } else { 214 nukees2.put(user, nukees.get(username)); 215 } 216 } 217 String toDirPath; 219 String toName = "[NUKED]-" + nukeDir.getName(); 220 try { 221 toDirPath = nukeDir.getParentFile().getPath(); 222 } catch (FileNotFoundException ex) { 223 logger.fatal("", ex); 224 return FtpReply.RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN; 225 } 226 try { 227 nukeDir = nukeDir.renameTo(toDirPath, toName); 228 nukeDir.createDirectory( 229 conn.getUserNull().getUsername(), 230 conn.getUserNull().getGroupName(), 231 "REASON-" + reason); 232 } catch (IOException ex) { 233 logger.warn("", ex); 234 response.addComment( 235 " cannot rename to \"" 236 + toDirPath 237 + "/" 238 + toName 239 + "\": " 240 + ex.getMessage()); 241 response.setCode(500); 242 response.setMessage("NUKE failed"); 243 return response; 244 } 245 246 long nukeDirSize = 0; 247 long nukedAmount = 0; 248 249 for (Iterator iter = nukees2.keySet().iterator(); iter.hasNext();) { 251 AbstractUser nukee = (AbstractUser) iter.next(); 252 if (nukee == null) 253 continue; 254 long size = ((Long ) nukees2.get(nukee)).longValue(); 255 256 long debt = 257 calculateNukedAmount(size, nukee.getRatio(), multiplier); 258 259 nukedAmount += debt; 260 nukeDirSize += size; 261 nukee.updateCredits(-debt); 262 nukee.updateUploadedBytes(-size); 263 nukee.updateNukedBytes(debt); 264 nukee.updateTimesNuked(1); 265 nukee.setLastNuked(System.currentTimeMillis()); 266 try { 267 nukee.commit(); 268 } catch (UserFileException e1) { 269 response.addComment( 270 "Error writing userfile: " + e1.getMessage()); 271 logger.log(Level.WARN, "Error writing userfile", e1); 272 } 273 response.addComment( 274 nukee.getUsername() + " " + Bytes.formatBytes(debt)); 275 } 276 NukeEvent nuke = 277 new NukeEvent( 278 conn.getUserNull(), 279 "NUKE", 280 nukeDirPath, 281 nukeDirSize, 282 nukedAmount, 283 multiplier, 284 reason, 285 nukees); 286 getNukeLog().add(nuke); 287 conn.getConnectionManager().dispatchFtpEvent(nuke); 288 return response; 289 } 290 291 private FtpReply doSITE_NUKES(BaseFtpConnection conn) { 292 FtpReply response = (FtpReply) FtpReply.RESPONSE_200_COMMAND_OK.clone(); 293 for (Iterator iter = getNukeLog().getAll().iterator(); 294 iter.hasNext(); 295 ) { 296 response.addComment(iter.next()); 297 } 298 return response; 299 } 300 301 315 private FtpReply doSITE_UNNUKE(BaseFtpConnection conn) { 316 if (!conn.getUserNull().isNuker()) 317 return FtpReply.RESPONSE_530_ACCESS_DENIED; 318 319 StringTokenizer st = 320 new StringTokenizer (conn.getRequest().getArgument()); 321 if (!st.hasMoreTokens()) { 322 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 323 } 324 325 String toName = st.nextToken(); 326 String toPath; 327 { 328 StringBuffer toPath2 = 329 new StringBuffer (conn.getCurrentDirectory().getPath()); 330 if (toPath2.length() != 1) 331 toPath2.append("/"); toPath2.append(toName); 333 toPath = toPath2.toString(); 334 } 335 String toDir = conn.getCurrentDirectory().getPath(); 336 String nukeName = "[NUKED]-" + toName; 337 338 String reason; 339 if (st.hasMoreTokens()) { 340 reason = st.nextToken(""); 341 } else { 342 reason = ""; 343 } 344 345 LinkedRemoteFileInterface nukeDir; 346 try { 347 nukeDir = conn.getCurrentDirectory().getFile(nukeName); 348 } catch (FileNotFoundException e2) { 349 return new FtpReply( 350 200, 351 nukeName + " doesn't exist: " + e2.getMessage()); 352 } 353 354 FtpReply response = (FtpReply) FtpReply.RESPONSE_200_COMMAND_OK.clone(); 355 NukeEvent nuke; 356 try { 357 nuke = getNukeLog().get(toPath); 358 } catch (ObjectNotFoundException ex) { 359 response.addComment(ex.getMessage()); 360 return response; 361 } 362 363 for (Iterator iter = nuke.getNukees2().iterator(); iter.hasNext();) { 368 Nukee nukeeObj = (Nukee) iter.next(); 370 String nukeeName = nukeeObj.getUsername(); 372 User nukee; 373 try { 374 nukee = 375 conn.getConnectionManager().getUserManager().getUserByName( 376 nukeeName); 377 } catch (NoSuchUserException e) { 378 response.addComment(nukeeName + ": no such user"); 379 continue; 380 } catch (UserFileException e) { 381 response.addComment(nukeeName + ": error reading userfile"); 382 logger.fatal("error reading userfile", e); 383 continue; 384 } 385 long nukedAmount = 386 calculateNukedAmount( 387 nukeeObj.getAmount(), 388 nukee.getRatio(), 389 nuke.getMultiplier()); 390 391 nukee.updateCredits(nukedAmount); 392 nukee.updateUploadedBytes(nukeeObj.getAmount()); 393 nukee.updateTimesNuked(-1); 394 395 try { 396 nukee.commit(); 397 } catch (UserFileException e3) { 398 logger.log( 399 Level.FATAL, 400 "Eroror saveing userfile for " + nukee.getUsername(), 401 e3); 402 response.addComment( 403 "Error saving userfile for " + nukee.getUsername()); 404 } 405 406 response.addComment( 407 nukeeName + ": restored " + Bytes.formatBytes(nukedAmount)); 408 } 409 try { 410 getNukeLog().remove(toPath); 411 } catch (ObjectNotFoundException e) { 412 response.addComment("Error removing nukelog entry"); 413 } 414 try { 415 nukeDir = nukeDir.renameTo(toDir, toName); 416 } catch (FileExistsException e1) { 417 response.addComment( 418 "Error renaming nuke, target dir already exists"); 419 } catch (IOException e1) { 420 response.addComment("Error: " + e1.getMessage()); 421 logger.log( 422 Level.FATAL, 423 "Illegaltargetexception: means parent doesn't exist", 424 e1); 425 } 426 427 try { 428 LinkedRemoteFileInterface reasonDir = 429 nukeDir.getFile("REASON-" + nuke.getReason()); 430 if (reasonDir.isDirectory()) 431 reasonDir.delete(); 432 } catch (FileNotFoundException e3) { 433 logger.debug( 434 "Failed to delete 'REASON-" + reason + "' dir in UNNUKE", 435 e3); 436 } 437 438 nuke.setCommand("UNNUKE"); 439 nuke.setReason(reason); 440 nuke.setUser(conn.getUserNull()); 441 conn.getConnectionManager().dispatchFtpEvent(nuke); 442 return response; 443 } 444 445 public FtpReply execute(BaseFtpConnection conn) 446 throws UnhandledCommandException { 447 if (_nukelog == null) { 448 return new FtpReply(500, "You must reconnect to use NUKE"); 449 } 450 String cmd = conn.getRequest().getCommand(); 451 if ("SITE NUKE".equals(cmd)) 452 return doSITE_NUKE(conn); 453 if ("SITE NUKES".equals(cmd)) 454 return doSITE_NUKES(conn); 455 if ("SITE UNNUKE".equals(cmd)) 456 return doSITE_UNNUKE(conn); 457 throw UnhandledCommandException.create(Nuke.class, conn.getRequest()); 458 } 459 460 public String [] getFeatReplies() { 461 return null; 462 } 463 464 private NukeLog getNukeLog() { 465 return _nukelog; 466 } 467 468 public CommandHandler initialize( 469 BaseFtpConnection conn, 470 CommandManager initializer) { 471 return this; 472 } 473 474 public void load(CommandManagerFactory initializer) { 475 _nukelog = new NukeLog(); 476 try { 477 Document doc = 478 new SAXBuilder().build(new FileReader ("nukelog.xml")); 479 List nukes = doc.getRootElement().getChildren(); 480 for (Iterator iter = nukes.iterator(); iter.hasNext();) { 481 Element nukeElement = (Element) iter.next(); 482 483 User user = 484 initializer 485 .getConnectionManager() 486 .getUserManager() 487 .getUserByName( 488 nukeElement.getChildText("user")); 489 String directory = nukeElement.getChildText("path"); 490 long time = Long.parseLong(nukeElement.getChildText("time")); 491 int multiplier = 492 Integer.parseInt(nukeElement.getChildText("multiplier")); 493 String reason = nukeElement.getChildText("reason"); 494 495 long size = Long.parseLong(nukeElement.getChildText("size")); 496 long nukedAmount = 497 Long.parseLong(nukeElement.getChildText("nukedAmount")); 498 499 Map nukees = new Hashtable (); 500 List nukeesElement = 501 nukeElement.getChild("nukees").getChildren("nukee"); 502 for (Iterator iterator = nukeesElement.iterator(); 503 iterator.hasNext(); 504 ) { 505 Element nukeeElement = (Element) iterator.next(); 506 String nukeeUsername = 507 nukeeElement.getChildText("username"); 508 Long nukeeAmount = 509 new Long (nukeeElement.getChildText("amount")); 510 511 nukees.put(nukeeUsername, nukeeAmount); 512 } 513 _nukelog.add( 514 new NukeEvent( 515 user, 516 "NUKE", 517 directory, 518 time, 519 size, 520 nukedAmount, 521 multiplier, 522 reason, 523 nukees)); 524 } 525 } catch (FileNotFoundException ex) { 526 logger.log( 527 Level.DEBUG, 528 "nukelog.xml not found, will create it after first nuke."); 529 } catch (Exception ex) { 530 logger.log( 531 Level.INFO, 532 "Error loading nukelog from nukelog.xml", 533 ex); 534 } 535 } 536 public void unload() { 537 _nukelog = null; 538 } 539 540 } 541 | Popular Tags |