KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > drftpd > master > command > plugins > DataConnectionHandler


1 /*
2  * This file is part of DrFTPD, Distributed FTP Daemon.
3  *
4  * DrFTPD is free software; you can redistribute it and/or modify it under the
5  * terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * DrFTPD is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * DrFTPD; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
15  * Suite 330, Boston, MA 02111-1307 USA
16  */

17 package net.sf.drftpd.master.command.plugins;
18 import java.io.FileNotFoundException JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.PrintWriter JavaDoc;
21 import java.net.BindException JavaDoc;
22 import java.net.InetAddress JavaDoc;
23 import java.net.InetSocketAddress JavaDoc;
24 import java.net.ServerSocket JavaDoc;
25 import java.net.Socket JavaDoc;
26 import java.net.UnknownHostException JavaDoc;
27 import java.rmi.RemoteException JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.StringTokenizer JavaDoc;
33
34 import javax.net.SocketFactory;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.SSLSocket;
37 import javax.net.ssl.SSLSocketFactory;
38
39 import net.sf.drftpd.Bytes;
40 import net.sf.drftpd.Checksum;
41 import net.sf.drftpd.FileExistsException;
42 import net.sf.drftpd.NoAvailableSlaveException;
43 import net.sf.drftpd.NoSFVEntryException;
44 import net.sf.drftpd.SFVFile;
45 import net.sf.drftpd.SlaveUnavailableException;
46 import net.sf.drftpd.event.TransferEvent;
47 import net.sf.drftpd.master.BaseFtpConnection;
48 import net.sf.drftpd.master.FtpReply;
49 import net.sf.drftpd.master.FtpRequest;
50 import net.sf.drftpd.master.RemoteSlave;
51 import net.sf.drftpd.master.command.CommandManager;
52 import net.sf.drftpd.master.command.CommandManagerFactory;
53 import net.sf.drftpd.master.usermanager.UserFileException;
54 import net.sf.drftpd.remotefile.LinkedRemoteFile;
55 import net.sf.drftpd.remotefile.LinkedRemoteFileInterface;
56 import net.sf.drftpd.remotefile.StaticRemoteFile;
57 import net.sf.drftpd.slave.Transfer;
58 import net.sf.drftpd.slave.TransferFailedException;
59 import net.sf.drftpd.slave.TransferStatus;
60 import net.sf.drftpd.util.ListUtils;
61 import net.sf.drftpd.util.PortRange;
62 import net.sf.drftpd.util.SSLGetContext;
63
64 import org.apache.log4j.Level;
65 import org.apache.log4j.Logger;
66 import org.drftpd.commands.CommandHandler;
67 import org.drftpd.commands.CommandHandlerFactory;
68 import org.drftpd.commands.UnhandledCommandException;
69 import org.tanesha.replacer.ReplacerEnvironment;
70 /**
71  * @author mog
72  * @author zubov
73  * @version $Id: DataConnectionHandler.java,v 1.57.2.1 2004/06/19 23:37:26 mog Exp $
74  */

75 public class DataConnectionHandler implements CommandHandlerFactory, CommandHandler, Cloneable JavaDoc {
76     private static final Logger logger = Logger
77             .getLogger(DataConnectionHandler.class);
78     private SSLContext _ctx;
79     private boolean _encryptedDataChannel;
80     protected boolean _isPasv = false;
81     protected boolean _isPort = false;
82     /**
83      * Holds the address that getDataSocket() should connect to in PORT mode.
84      */

85     private InetSocketAddress JavaDoc _portAddress;
86     private PortRange _portRange = new PortRange();
87     protected boolean _preTransfer = false;
88     private RemoteSlave _preTransferRSlave;
89     private long _resumePosition = 0;
90     private RemoteSlave _rslave;
91     /**
92      * ServerSocket for PASV mode.
93      */

94     private ServerSocket JavaDoc _serverSocket;
95     private Transfer _transfer;
96     private LinkedRemoteFileInterface _transferFile;
97     private char type = 'A';
98     public DataConnectionHandler() {
99         super();
100         try {
101             _ctx = SSLGetContext.getSSLContext();
102         } catch (Exception JavaDoc e) {
103             _ctx = null;
104             logger.warn("Couldn't load SSLContext, SSL/TLS disabled", e);
105         }
106     }
107     private FtpReply doAUTH(BaseFtpConnection conn) {
108         if (_ctx == null)
109             return new FtpReply(500, "TLS not configured");
110         Socket JavaDoc s = conn.getControlSocket();
111         //reply success
112
conn.getControlWriter().write(
113                 new FtpReply(234, conn.getRequest().getCommandLine()
114                         + " successfull").toString());
115         conn.getControlWriter().flush();
116         try {
117             SSLSocket s2;
118             s2 = (SSLSocket) ((SSLSocketFactory) _ctx.getSocketFactory())
119                     .createSocket(s, s.getInetAddress().getHostAddress(), s
120                             .getPort(), true);
121             s2.setUseClientMode(false);
122             s2.startHandshake();
123             conn.setControlSocket(s2);
124         } catch (IOException JavaDoc e) {
125             logger.warn("", e);
126             conn.stop(e.getMessage());
127             return null;
128         }
129         return null;
130     }
131     /**
132      * <code>APPE &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
133      *
134      * This command causes the server-DTP to accept the data transferred via the
135      * data connection and to store the data in a file at the server site. If
136      * the file specified in the pathname exists at the server site, then the
137      * data shall be appended to that file; otherwise the file specified in the
138      * pathname shall be created at the server site.
139      */

140     //TODO implement APPE with transfer()
141
/*
142      * public void doAPPE(FtpRequest request, PrintWriter out) {
143      * // reset state variables resetState();
144      * // argument check if(!request.hasArgument()) {
145      * out.print(FtpResponse.RESPONSE_501_SYNTAX_ERROR); return; }
146      * // get filenames String fileName = request.getArgument(); fileName =
147      * user.getVirtualDirectory().getAbsoluteName(fileName); String physicalName =
148      * user.getVirtualDirectory().getPhysicalName(fileName); File requestedFile =
149      * new File(physicalName); String args[] = {fileName};
150      * // check permission
151      * if(!user.getVirtualDirectory().hasWritePermission(physicalName, true)) {
152      * out.write(ftpStatus.getResponse(450, request, user, args)); return; }
153      * // now transfer file data out.write(ftpStatus.getResponse(150, request,
154      * user, args)); InputStream is = null; OutputStream os = null; try { Socket
155      * dataSoc = mDataConnection.getDataSocket(); if (dataSoc == null) {
156      * out.write(ftpStatus.getResponse(550, request, user, args)); return; }
157      *
158      * is = dataSoc.getInputStream(); RandomAccessFile raf = new
159      * RandomAccessFile(requestedFile, "rw"); raf.seek(raf.length()); os =
160      * user.getOutputStream( new FileOutputStream(raf.getFD()) );
161      *
162      * StreamConnector msc = new StreamConnector(is, os);
163      * msc.setMaxTransferRate(user.getMaxUploadRate()); msc.setObserver(this);
164      * msc.connect();
165      *
166      * if(msc.hasException()) { out.write(ftpStatus.getResponse(451, request,
167      * user, args)); } else { mConfig.getStatistics().setUpload(requestedFile,
168      * user, msc.getTransferredSize()); }
169      *
170      * out.write(ftpStatus.getResponse(226, request, user, args)); }
171      * catch(IOException ex) { out.write(ftpStatus.getResponse(425, request,
172      * user, args)); } finally { try { is.close(); os.close();
173      * mDataConnection.reset(); } catch(Exception ex) { ex.printStackTrace(); } } }
174      */

175     /**
176      * <code>MODE &lt;SP&gt; <mode-code> &lt;CRLF&gt;</code><br>
177      *
178      * The argument is a single Telnet character code specifying the data
179      * transfer modes described in the Section on Transmission Modes.
180      */

181     private FtpReply doMODE(BaseFtpConnection conn) {
182         FtpRequest request = conn.getRequest();
183         // argument check
184
if (!request.hasArgument()) {
185             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
186         }
187         if (request.getArgument().equalsIgnoreCase("S")) {
188             return FtpReply.RESPONSE_200_COMMAND_OK;
189         } else {
190             return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;
191         }
192     }
193     /**
194      * <code>PASV &lt;CRLF&gt;</code><br>
195      *
196      * This command requests the server-DTP to "listen" on a data port (which is
197      * not its default data port) and to wait for a connection rather than
198      * initiate one upon receipt of a transfer command. The response to this
199      * command includes the host and port address this server is listening on.
200      */

201     private FtpReply doPASV(BaseFtpConnection conn) {
202         if (!_preTransfer) {
203             return new FtpReply(500,
204                     "You need to use a client supporting PRET (PRE Transfer) to use PASV");
205         }
206         //reset();
207
_preTransfer = false;
208         if(isPort() == true) throw new RuntimeException JavaDoc();
209         InetSocketAddress JavaDoc address;
210         if (_preTransferRSlave == null) {
211             try {
212                 address = new InetSocketAddress JavaDoc(conn.getControlSocket()
213                         .getLocalAddress(), _portRange.getPort());
214                 _serverSocket = (_encryptedDataChannel ? _ctx
215                         .getServerSocketFactory() : conn
216                         .getServerSocketFactory()).createServerSocket();
217                 _serverSocket.bind(address, 1);
218                 _serverSocket.setSoTimeout(60000);
219                 // _address2 =
220
// new InetSocketAddress(
221
// _serverSocket.getInetAddress(),
222
// _serverSocket.getLocalPort());
223
_isPasv = true;
224             } catch (BindException JavaDoc ex) {
225                 _serverSocket = null;
226                 logger.warn("", ex);
227                 return new FtpReply(550, ex.getMessage());
228             } catch (Exception JavaDoc ex) {
229                 logger.log(Level.WARN, "", ex);
230                 return new FtpReply(550, ex.getMessage());
231             }
232         } else {
233             try {
234                 _transfer = _preTransferRSlave.getSlave().listen(false);
235                 address = new InetSocketAddress JavaDoc(_preTransferRSlave
236                         .getInetAddress(), _transfer.getLocalPort());
237                 _isPasv = true;
238             } catch (RemoteException JavaDoc e) {
239                 _preTransferRSlave.handleRemoteException(e);
240                 return new FtpReply(450, "Remote error: " + e.getMessage());
241             } catch (SlaveUnavailableException e) {
242                 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE;
243             } catch (IOException JavaDoc e) {
244                 logger.log(Level.FATAL, "", e);
245                 return new FtpReply(450, e.getMessage());
246             }
247         }
248         //InetAddress mAddress == getInetAddress();
249
//miPort == getPort();
250
String JavaDoc addrStr = address.getAddress().getHostAddress()
251                 .replace('.', ',')
252                 + ','
253                 + (address.getPort() >> 8)
254                 + ','
255                 + (address.getPort() & 0xFF);
256         return new FtpReply(227, "Entering Passive Mode (" + addrStr + ").");
257     }
258     private FtpReply doPBSZ(BaseFtpConnection conn)
259             throws UnhandledCommandException {
260         String JavaDoc cmd = conn.getRequest().getArgument();
261         if (cmd == null || !cmd.equals("0"))
262             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
263         return FtpReply.RESPONSE_200_COMMAND_OK;
264     }
265     /**
266      * <code>PORT &lt;SP&gt; <host-port> &lt;CRLF&gt;</code><br>
267      *
268      * The argument is a HOST-PORT specification for the data port to be used in
269      * data connection. There are defaults for both the user and server data
270      * ports, and under normal circumstances this command and its reply are not
271      * needed. If this command is used, the argument is the concatenation of a
272      * 32-bit internet host address and a 16-bit TCP port address. This address
273      * information is broken into 8-bit fields and the value of each field is
274      * transmitted as a decimal number (in character string representation). The
275      * fields are separated by commas. A port command would be:
276      *
277      * PORT h1,h2,h3,h4,p1,p2
278      *
279      * where h1 is the high order 8 bits of the internet host address.
280      */

281     private FtpReply doPORT(BaseFtpConnection conn) {
282         FtpRequest request = conn.getRequest();
283         reset();
284         InetAddress JavaDoc clientAddr = null;
285         // argument check
286
if (!request.hasArgument()) {
287             //Syntax error in parameters or arguments
288
return FtpReply.RESPONSE_501_SYNTAX_ERROR;
289         }
290         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(request.getArgument(), ",");
291         if (st.countTokens() != 6) {
292             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
293         }
294         // get data server
295
String JavaDoc dataSrvName = st.nextToken() + '.' + st.nextToken() + '.'
296                 + st.nextToken() + '.' + st.nextToken();
297         try {
298             clientAddr = InetAddress.getByName(dataSrvName);
299         } catch (UnknownHostException JavaDoc ex) {
300             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
301         }
302         String JavaDoc portHostAddress = clientAddr.getHostAddress();
303         String JavaDoc clientHostAddress = conn.getControlSocket().getInetAddress()
304                 .getHostAddress();
305         if ((portHostAddress.startsWith("192.168.") && !clientHostAddress
306                 .startsWith("192.168."))
307                 || (portHostAddress.startsWith("10.") && !clientHostAddress
308                         .startsWith("10."))) {
309             FtpReply response = new FtpReply(501);
310             response.addComment("==YOU'RE BEHIND A NAT ROUTER==");
311             response
312                     .addComment("Configure the firewall settings of your FTP client");
313             response
314                     .addComment(" to use your real IP: "
315                             + conn.getControlSocket().getInetAddress()
316                                     .getHostAddress());
317             response.addComment("And set up port forwarding in your router.");
318             response
319                     .addComment("Or you can just use a PRET capable client, see");
320             response
321                     .addComment(" http://drftpd.org/ for PRET capable clients");
322             return response;
323         }
324         int clientPort;
325         // get data server port
326
try {
327             int hi = Integer.parseInt(st.nextToken());
328             int lo = Integer.parseInt(st.nextToken());
329             clientPort = (hi << 8) | lo;
330         } catch (NumberFormatException JavaDoc ex) {
331             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
332             //out.write(ftpStatus.getResponse(552, request, user, null));
333
}
334         _isPort = true;
335         _portAddress = new InetSocketAddress JavaDoc(clientAddr, clientPort);
336         if (portHostAddress.startsWith("127.")) {
337             return new FtpReply(200,
338                     "Ok, but distributed transfers won't work with local addresses");
339         }
340         //Notify the user that this is not his IP.. Good for NAT users that
341
// aren't aware that their IP has changed.
342
if (!clientAddr.equals(conn.getControlSocket().getInetAddress())) {
343             return new FtpReply(200,
344                     "FXP allowed. If you're not FXPing and set your IP to "
345                             + conn.getControlSocket().getInetAddress()
346                                     .getHostAddress()
347                             + " (usually in firewall settings)");
348         }
349         return FtpReply.RESPONSE_200_COMMAND_OK;
350     }
351     private FtpReply doPRET(BaseFtpConnection conn) {
352         reset();
353         FtpRequest request = conn.getRequest();
354         FtpRequest ghostRequest = new FtpRequest(request.getArgument());
355         String JavaDoc cmd = ghostRequest.getCommand();
356         if (cmd.equals("LIST") || cmd.equals("NLST") || cmd.equals("MLSD")) {
357             _preTransferRSlave = null;
358             _preTransfer = true;
359             return new FtpReply(200,
360                     "OK, will use master for upcoming transfer");
361         } else if (cmd.equals("RETR")) {
362             try {
363                 LinkedRemoteFileInterface downFile = conn.getCurrentDirectory()
364                         .lookupFile(ghostRequest.getArgument());
365                 _preTransferRSlave = conn.getSlaveManager()
366                         .getSlaveSelectionManager().getASlave(
367                                 downFile.getAvailableSlaves(),
368                                 Transfer.TRANSFER_SENDING_DOWNLOAD, conn,
369                                 downFile);
370                 _preTransfer = true;
371                 return new FtpReply(200, "OK, will use "
372                         + _preTransferRSlave.getName()
373                         + " for upcoming transfer");
374             } catch (NoAvailableSlaveException e) {
375                 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE;
376             } catch (FileNotFoundException JavaDoc e) {
377                 return FtpReply.RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN;
378             }
379         } else if (cmd.equals("STOR")) {
380             LinkedRemoteFile.NonExistingFile nef = conn.getCurrentDirectory()
381                     .lookupNonExistingFile(ghostRequest.getArgument());
382             if (nef.exists()) {
383                 return FtpReply.RESPONSE_530_ACCESS_DENIED;
384             }
385             if (!ListUtils.isLegalFileName(nef.getPath())) {
386                 return FtpReply.RESPONSE_530_ACCESS_DENIED;
387             }
388             try {
389                 _preTransferRSlave = conn.getSlaveManager()
390                         .getSlaveSelectionManager().getASlave(
391                                 conn.getSlaveManager().getAvailableSlaves(),
392                                 Transfer.TRANSFER_RECEIVING_UPLOAD, conn,
393                                 nef.getFile());
394                 _preTransfer = true;
395                 return new FtpReply(200, "OK, will use "
396                         + _preTransferRSlave.getName()
397                         + " for upcoming transfer");
398             } catch (NoAvailableSlaveException e) {
399                 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE;
400             }
401         } else {
402             return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;
403         }
404     }
405     private FtpReply doPROT(BaseFtpConnection conn)
406             throws UnhandledCommandException {
407         if (_ctx == null)
408             return new FtpReply(500, "TLS not configured");
409         FtpRequest req = conn.getRequest();
410         if (!req.hasArgument() || req.getArgument().length() != 1)
411             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
412         switch (Character.toUpperCase(req.getArgument().charAt(0))) {
413             case 'C' :
414                 //clear
415
_encryptedDataChannel = false;
416                 return FtpReply.RESPONSE_200_COMMAND_OK;
417             case 'P' :
418                 //private
419
_encryptedDataChannel = true;
420                 return FtpReply.RESPONSE_200_COMMAND_OK;
421             default :
422                 return FtpReply.RESPONSE_501_SYNTAX_ERROR;
423         }
424     }
425     /**
426      * <code>REST &lt;SP&gt; <marker> &lt;CRLF&gt;</code><br>
427      *
428      * The argument field represents the server marker at which file transfer is
429      * to be restarted. This command does not cause file transfer but skips over
430      * the file to the specified data checkpoint. This command shall be
431      * immediately followed by the appropriate FTP service command which shall
432      * cause file transfer to resume.
433      */

434     private FtpReply doREST(BaseFtpConnection conn) {
435         FtpRequest request = conn.getRequest();
436         // argument check
437
if (!request.hasArgument()) {
438             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
439         }
440         String JavaDoc skipNum = request.getArgument();
441         try {
442             _resumePosition = Long.parseLong(skipNum);
443         } catch (NumberFormatException JavaDoc ex) {
444             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
445         }
446         if (_resumePosition < 0) {
447             _resumePosition = 0;
448             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
449         }
450         return FtpReply.RESPONSE_350_PENDING_FURTHER_INFORMATION;
451     }
452     private FtpReply doSITE_RESCAN(BaseFtpConnection conn) {
453         FtpRequest request = conn.getRequest();
454         boolean forceRescan = (request.hasArgument() && request.getArgument()
455                 .equalsIgnoreCase("force"));
456         LinkedRemoteFileInterface directory = conn.getCurrentDirectory();
457         SFVFile sfv;
458         try {
459             sfv = conn.getCurrentDirectory().lookupSFVFile();
460         } catch (Exception JavaDoc e) {
461             return new FtpReply(200, "Error getting SFV File: "
462                     + e.getMessage());
463         }
464         PrintWriter JavaDoc out = conn.getControlWriter();
465         for (Iterator JavaDoc i = sfv.getEntries().entrySet().iterator(); i.hasNext();) {
466             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
467             String JavaDoc fileName = (String JavaDoc) entry.getKey();
468             Long JavaDoc checkSum = (Long JavaDoc) entry.getValue();
469             LinkedRemoteFileInterface file;
470             try {
471                 file = directory.lookupFile(fileName);
472             } catch (FileNotFoundException JavaDoc ex) {
473                 out.write("200- SFV: "
474                         + Checksum.formatChecksum(checkSum.longValue())
475                         + " SLAVE: " + fileName + " MISSING"
476                         + BaseFtpConnection.NEWLINE);
477                 continue;
478             }
479             String JavaDoc status;
480             long fileCheckSum;
481             try {
482                 if (forceRescan) {
483                     fileCheckSum = file.getCheckSumFromSlave();
484                 } else {
485                     fileCheckSum = file.getCheckSum();
486                 }
487             } catch (NoAvailableSlaveException e1) {
488                 out.println("200- " + fileName + "SFV: "
489                         + Checksum.formatChecksum(checkSum.longValue())
490                         + " SLAVE: OFFLINE");
491                 continue;
492             } catch (IOException JavaDoc ex) {
493                 out.print("200- " + fileName + " SFV: "
494                         + Checksum.formatChecksum(checkSum.longValue())
495                         + " SLAVE: IO error: " + ex.getMessage());
496                 continue;
497             }
498             if (fileCheckSum == 0L) {
499                 status = "FAILED - failed to checksum file";
500             } else if (checkSum.longValue() == fileCheckSum) {
501                 status = "OK";
502             } else {
503                 status = "FAILED - checksum missmatch";
504             }
505             out.println("200- " + fileName + " SFV: "
506                     + Checksum.formatChecksum(checkSum.longValue())
507                     + " SLAVE: "
508                     + Checksum.formatChecksum(checkSum.longValue()) + " "
509                     + status);
510             continue;
511         }
512         return FtpReply.RESPONSE_200_COMMAND_OK;
513     }
514     private FtpReply doSITE_XDUPE(BaseFtpConnection conn) {
515         return FtpReply.RESPONSE_502_COMMAND_NOT_IMPLEMENTED;
516         // resetState();
517
//
518
// if (!request.hasArgument()) {
519
// if (this.xdupe == 0) {
520
// out.println("200 Extended dupe mode is disabled.");
521
// } else {
522
// out.println(
523
// "200 Extended dupe mode " + this.xdupe + " is enabled.");
524
// }
525
// return;
526
// }
527
//
528
// short myXdupe;
529
// try {
530
// myXdupe = Short.parseShort(request.getArgument());
531
// } catch (NumberFormatException ex) {
532
// out.print(FtpResponse.RESPONSE_501_SYNTAX_ERROR);
533
// return;
534
// }
535
//
536
// if (myXdupe > 0 || myXdupe < 4) {
537
// out.print(
538
// FtpResponse.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM);
539
// return;
540
// }
541
// this.xdupe = myXdupe;
542
// out.println("200 Activated extended dupe mode " + myXdupe + ".");
543
}
544     /**
545      * <code>STRU &lt;SP&gt; &lt;structure-code&gt; &lt;CRLF&gt;</code><br>
546      *
547      * The argument is a single Telnet character code specifying file structure.
548      */

549     private FtpReply doSTRU(BaseFtpConnection conn) {
550         FtpRequest request = conn.getRequest();
551         // argument check
552
if (!request.hasArgument()) {
553             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
554         }
555         if (request.getArgument().equalsIgnoreCase("F")) {
556             return FtpReply.RESPONSE_200_COMMAND_OK;
557         } else {
558             return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;
559         }
560         /*
561          * if (setStructure(request.getArgument().charAt(0))) { return
562          * FtpResponse.RESPONSE_200_COMMAND_OK); } else { return
563          * FtpResponse.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM); }
564          */

565     }
566     /**
567      * <code>SYST &lt;CRLF&gt;</code><br>
568      *
569      * This command is used to find out the type of operating system at the
570      * server.
571      */

572     private FtpReply doSYST(BaseFtpConnection conn) {
573         /*
574          * String systemName = System.getProperty("os.name"); if(systemName ==
575          * null) { systemName = "UNKNOWN"; } else { systemName =
576          * systemName.toUpperCase(); systemName = systemName.replace(' ', '-'); }
577          * String args[] = {systemName};
578          */

579         return FtpReply.RESPONSE_215_SYSTEM_TYPE;
580         //String args[] = { "UNIX" };
581
//out.write(ftpStatus.getResponse(215, request, user, args));
582
}
583     /**
584      * <code>TYPE &lt;SP&gt; &lt;type-code&gt; &lt;CRLF&gt;</code><br>
585      *
586      * The argument specifies the representation type.
587      */

588     private FtpReply doTYPE(BaseFtpConnection conn) {
589         FtpRequest request = conn.getRequest();
590         // get type from argument
591
if (!request.hasArgument()) {
592             return FtpReply.RESPONSE_501_SYNTAX_ERROR;
593         }
594         // set it
595
if (setType(request.getArgument().charAt(0))) {
596             return FtpReply.RESPONSE_200_COMMAND_OK;
597         } else {
598             return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;
599         }
600     }
601     public FtpReply execute(BaseFtpConnection conn)
602             throws UnhandledCommandException {
603         String JavaDoc cmd = conn.getRequest().getCommand();
604         if ("MODE".equals(cmd))
605             return doMODE(conn);
606         if ("PASV".equals(cmd))
607             return doPASV(conn);
608         if ("PORT".equals(cmd))
609             return doPORT(conn);
610         if ("PRET".equals(cmd))
611             return doPRET(conn);
612         if ("REST".equals(cmd))
613             return doREST(conn);
614         if ("RETR".equals(cmd) || "STOR".equals(cmd) || "APPE".equals(cmd))
615             return transfer(conn);
616         if ("SITE RESCAN".equals(cmd))
617             return doSITE_RESCAN(conn);
618         if ("SITE XDUPE".equals(cmd))
619             return doSITE_XDUPE(conn);
620         if ("STRU".equals(cmd))
621             return doSTRU(conn);
622         if ("SYST".equals(cmd))
623             return doSYST(conn);
624         if ("TYPE".equals(cmd))
625             return doTYPE(conn);
626         if ("AUTH".equals(cmd))
627             return doAUTH(conn);
628         if ("PROT".equals(cmd))
629             return doPROT(conn);
630         if ("PBSZ".equals(cmd))
631             return doPBSZ(conn);
632         throw UnhandledCommandException.create(DataConnectionHandler.class,
633                 conn.getRequest());
634     }
635     /**
636      * Get the data socket. In case of error returns null.
637      *
638      * Used by LIST and NLST and MLST.
639      */

640     public Socket JavaDoc getDataSocket(SocketFactory socketFactory) throws IOException JavaDoc {
641         Socket JavaDoc dataSocket;
642         // get socket depending on the selection
643
if (isPort()) {
644             try {
645                 SocketFactory ssf = _encryptedDataChannel ? _ctx
646                         .getSocketFactory() : socketFactory;
647                 dataSocket = ssf.createSocket();
648                 //dataSocket.connect(_address, getPort());
649
dataSocket.connect(_portAddress);
650             } catch (IOException JavaDoc ex) {
651                 logger.warn("Error opening data socket", ex);
652                 dataSocket = null;
653                 throw ex;
654             }
655         } else if (isPasv()) {
656             try {
657                 dataSocket = _serverSocket.accept();
658             } finally {
659                 _serverSocket.close();
660                 _portRange.releasePort(_serverSocket.getLocalPort());
661                 _serverSocket = null;
662             }
663         } else {
664             throw new IllegalStateException JavaDoc("Neither PASV nor PORT");
665         }
666         if (_encryptedDataChannel) {
667             SSLSocket ssldatasocket = (SSLSocket) dataSocket;
668             ssldatasocket.setUseClientMode(false);
669             ssldatasocket.startHandshake();
670         }
671         dataSocket.setSoTimeout(15000); // 15 seconds timeout
672
return dataSocket;
673     }
674     public String JavaDoc[] getFeatReplies() {
675         if (_ctx != null)
676             return new String JavaDoc[]{"PRET", "AUTH SSL", "PBSZ"};
677         return new String JavaDoc[]{"PRET"};
678     }
679     /**
680      * Get client address from PORT command.
681      *
682      * @deprecated
683      */

684     // private InetAddress getInetAddress() {
685
// return _address;
686
// }
687
/**
688      * Get port number. return miPort
689      */

690     // private int getPort() {
691
// return _port;
692
// }
693
public RemoteSlave getTranferSlave() {
694         return _rslave;
695     }
696     public Transfer getTransfer() {
697         if (_transfer == null)
698             throw new IllegalStateException JavaDoc();
699         return _transfer;
700     }
701     public LinkedRemoteFileInterface getTransferFile() {
702         return _transferFile;
703     }
704     /**
705      * Get the user data type.
706      */

707     public char getType() {
708         return type;
709     }
710     public CommandHandler initialize(BaseFtpConnection conn,
711             CommandManager initializer) {
712         try {
713             return (DataConnectionHandler) clone();
714         } catch (CloneNotSupportedException JavaDoc e) {
715             throw new RuntimeException JavaDoc(e);
716         }
717     }
718     public boolean isEncryptedDataChannel() {
719         return _encryptedDataChannel;
720     }
721     /**
722      * Guarantes pre transfer is set up correctly.
723      */

724     public boolean isPasv() {
725         return _isPasv;
726     }
727     public boolean isPort() {
728         return _isPort;
729     }
730     public boolean isPreTransfer() {
731         return _preTransfer || isPasv();
732     }
733     public boolean isTransfering() {
734         return _transfer != null;
735     }
736     public void load(CommandManagerFactory initializer) {
737     }
738     protected void reset() {
739         _rslave = null;
740         _transfer = null;
741         _transferFile = null;
742         _preTransfer = false;
743         _preTransferRSlave = null;
744         if (_serverSocket != null) { //isPasv() && _preTransferRSlave == null
745
_portRange.releasePort(_serverSocket.getLocalPort());
746         }
747         _isPasv = false;
748         _serverSocket = null;
749         _isPort = false;
750         _resumePosition = 0;
751     }
752     /**
753      * Set the data type. Supported types are A (ascii) and I (binary).
754      *
755      * @return true if success
756      */

757     private boolean setType(char type) {
758         type = Character.toUpperCase(type);
759         if ((type != 'A') && (type != 'I')) {
760             return false;
761         }
762         this.type = type;
763         return true;
764     }
765     /**
766      * <code>STOU &lt;CRLF&gt;</code><br>
767      *
768      * This command behaves like STOR except that the resultant file is to be
769      * created in the current directory under a name unique to that directory.
770      * The 250 Transfer Started response must include the name generated.
771      */

772     //TODO STOU
773
/*
774      * public void doSTOU(FtpRequest request, PrintWriter out) {
775      * // reset state variables resetState();
776      * // get filenames String fileName =
777      * user.getVirtualDirectory().getAbsoluteName("ftp.dat"); String
778      * physicalName = user.getVirtualDirectory().getPhysicalName(fileName); File
779      * requestedFile = new File(physicalName); requestedFile =
780      * IoUtils.getUniqueFile(requestedFile); fileName =
781      * user.getVirtualDirectory().getVirtualName(requestedFile.getAbsolutePath());
782      * String args[] = {fileName};
783      * // check permission
784      * if(!user.getVirtualDirectory().hasCreatePermission(fileName, false)) {
785      * out.write(ftpStatus.getResponse(550, request, user, null)); return; }
786      * // now transfer file data out.print(FtpResponse.RESPONSE_150_OK);
787      * InputStream is = null; OutputStream os = null; try { Socket dataSoc =
788      * mDataConnection.getDataSocket(); if (dataSoc == null) {
789      * out.write(ftpStatus.getResponse(550, request, user, args)); return; }
790      *
791      *
792      * is = dataSoc.getInputStream(); os = user.getOutputStream( new
793      * FileOutputStream(requestedFile) );
794      *
795      * StreamConnector msc = new StreamConnector(is, os);
796      * msc.setMaxTransferRate(user.getMaxUploadRate()); msc.setObserver(this);
797      * msc.connect();
798      *
799      * if(msc.hasException()) { out.write(ftpStatus.getResponse(451, request,
800      * user, null)); return; } else {
801      * mConfig.getStatistics().setUpload(requestedFile, user,
802      * msc.getTransferredSize()); }
803      *
804      * out.write(ftpStatus.getResponse(226, request, user, null));
805      * mDataConnection.reset(); out.write(ftpStatus.getResponse(250, request,
806      * user, args)); } catch(IOException ex) {
807      * out.write(ftpStatus.getResponse(425, request, user, null)); } finally {
808      * IoUtils.close(is); IoUtils.close(os); mDataConnection.reset(); } }
809      */

810     /**
811      * <code>RETR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
812      *
813      * This command causes the server-DTP to transfer a copy of the file,
814      * specified in the pathname, to the server- or user-DTP at the other end of
815      * the data connection. The status and contents of the file at the server
816      * site shall be unaffected.
817      *
818      * RETR 125, 150 (110) 226, 250 425, 426, 451 450, 550 500, 501, 421, 530
819      * <p>
820      * <code>STOR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
821      *
822      * This command causes the server-DTP to accept the data transferred via the
823      * data connection and to store the data as a file at the server site. If
824      * the file specified in the pathname exists at the server site, then its
825      * contents shall be replaced by the data being transferred. A new file is
826      * created at the server site if the file specified in the pathname does not
827      * already exist.
828      *
829      * STOR 125, 150 (110) 226, 250 425, 426, 451, 551, 552 532, 450, 452, 553
830      * 500, 501, 421, 530
831      *
832      * ''zipscript?? renames bad uploads to .bad, how do we handle this with
833      * resumes?
834      */

835     //TODO add APPE support
836
private FtpReply transfer(BaseFtpConnection conn)
837             throws UnhandledCommandException {
838         if (!_encryptedDataChannel
839                 && conn.getConfig()
840                         .checkDenyDataUnencrypted(conn.getUserNull())) {
841             return new FtpReply(530, "USE SECURE DATA CONNECTION");
842         }
843         try {
844             FtpRequest request = conn.getRequest();
845             char direction = conn.getDirection();
846             String JavaDoc cmd = conn.getRequest().getCommand();
847             boolean isStor = cmd.equals("STOR");
848             boolean isRetr = cmd.equals("RETR");
849             boolean isAppe = cmd.equals("APPE");
850             boolean isStou = cmd.equals("STOU");
851             String JavaDoc eventType = isRetr ? "RETR" : "STOR";
852             if (isAppe || isStou)
853                 throw UnhandledCommandException.create(
854                         DataConnectionHandler.class, conn.getRequest());
855             // argument check
856
if (!request.hasArgument()) {
857                 return FtpReply.RESPONSE_501_SYNTAX_ERROR;
858             }
859             // get filenames
860
LinkedRemoteFileInterface targetDir;
861             String JavaDoc targetFileName;
862             if (isRetr) {
863                 try {
864                     _transferFile = conn.getCurrentDirectory().lookupFile(
865                             request.getArgument());
866                     if (!_transferFile.isFile()) {
867                         return new FtpReply(550, "Not a plain file");
868                     }
869                     targetDir = _transferFile.getParentFileNull();
870                     targetFileName = _transferFile.getName();
871                 } catch (FileNotFoundException JavaDoc ex) {
872                     return new FtpReply(550, ex.getMessage());
873                 }
874             } else if (isStor) {
875                 LinkedRemoteFile.NonExistingFile ret = conn
876                         .getCurrentDirectory().lookupNonExistingFile(
877                                 conn.getConnectionManager().getConfig()
878                                         .getFileName(request.getArgument()));
879                 targetDir = ret.getFile();
880                 targetFileName = ret.getPath();
881                 if (ret.exists()) {
882                     // target exists, this could be overwrite or resume
883
//TODO overwrite & resume files.
884
return new FtpReply(550,
885                             "Requested action not taken. File exists.");
886                     //_transferFile = targetDir;
887
//targetDir = _transferFile.getParent();
888
//if(_transfereFile.getOwner().equals(getUser().getUsername()))
889
// {
890
// // allow overwrite/resume
891
//}
892
//if(directory.isDirectory()) {
893
// return FtpReply.RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN;
894
//}
895
}
896                 if (!ListUtils.isLegalFileName(targetFileName)
897                         || !conn.getConfig().checkPrivPath(conn.getUserNull(),
898                                 targetDir)) {
899                     return new FtpReply(553,
900                             "Requested action not taken. File name not allowed.");
901                 }
902             } else {
903                 throw UnhandledCommandException.create(
904                         DataConnectionHandler.class, request);
905             }
906             //check access
907
if (!conn.getConfig().checkPrivPath(conn.getUserNull(), targetDir)) {
908                 return new FtpReply(550, request.getArgument()
909                         + ": No such file");
910             }
911             switch (direction) {
912                 case Transfer.TRANSFER_SENDING_DOWNLOAD :
913                     if (!conn.getConnectionManager().getConfig().checkDownload(
914                             conn.getUserNull(), targetDir)) {
915                         return FtpReply.RESPONSE_530_ACCESS_DENIED;
916                     }
917                     break;
918                 case Transfer.TRANSFER_RECEIVING_UPLOAD :
919                     if (!conn.getConnectionManager().getConfig().checkUpload(
920                             conn.getUserNull(), targetDir)) {
921                         return FtpReply.RESPONSE_530_ACCESS_DENIED;
922                     }
923                     break;
924                 default :
925                     throw UnhandledCommandException.create(
926                             DataConnectionHandler.class, request);
927             }
928             //check credits
929
if (isRetr) {
930                 if (conn.getUserNull().getRatio() != 0
931                         && conn.getUserNull().getCredits() < _transferFile
932                                 .length()) {
933                     return new FtpReply(550, "Not enough credits.");
934                 }
935             }
936             //setup _rslave
937
if (isPasv()) {
938                 // isPasv() means we're setup correctly
939
// if (!_preTransfer || _preTransferRSlave == null)
940
// return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;
941
//check pretransfer
942
if (isRetr
943                         && !_transferFile.getSlaves().contains(
944                                 _preTransferRSlave)) {
945                     return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;
946                 }
947                 _rslave = _preTransferRSlave;
948                 //_preTransferRSlave = null;
949
//_preTransfer = false;
950
//code above to be handled by reset()
951
} else {
952                 try {
953                     if (direction == Transfer.TRANSFER_SENDING_DOWNLOAD) {
954                         _rslave = conn.getConfig().getSlaveManager()
955                                 .getSlaveSelectionManager().getASlave(
956                                         _transferFile.getAvailableSlaves(),
957                                         Transfer.TRANSFER_SENDING_DOWNLOAD,
958                                         conn, _transferFile);
959                     } else if (direction == Transfer.TRANSFER_RECEIVING_UPLOAD) {
960                         _rslave = conn.getSlaveManager()
961                                 .getSlaveSelectionManager().getASlave(
962                                         conn.getSlaveManager()
963                                                 .getAvailableSlaves(),
964                                         Transfer.TRANSFER_RECEIVING_UPLOAD,
965                                         conn, targetDir);
966                     } else {
967                         throw new RuntimeException JavaDoc();
968                     }
969                 } catch (NoAvailableSlaveException ex) {
970                     return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE;
971                 }
972             }
973             if (isStor) {
974                 //setup upload
975
if(_rslave == null) throw new NullPointerException JavaDoc();
976                 List JavaDoc rslaves = Collections.singletonList(_rslave);
977                 StaticRemoteFile uploadFile = new StaticRemoteFile(rslaves,
978                         targetFileName, conn.getUserNull().getUsername(), conn
979                                 .getUserNull().getGroupName(), 0L, System
980                                 .currentTimeMillis(), 0L);
981                 _transferFile = targetDir.addFile(uploadFile);
982             }
983             // setup _transfer
984
if (isPort()) {
985                 try {
986                     _transfer = _rslave.getSlave().connect(_portAddress,
987                             _encryptedDataChannel);
988                 } catch (RemoteException JavaDoc ex) {
989                     _rslave.handleRemoteException(ex);
990                     return new FtpReply(450, "Remote error: " + ex.getMessage());
991                 } catch (Exception JavaDoc ex) {
992                     logger.fatal("rslave=" + _rslave, ex);
993                     return new FtpReply(450, ex.getClass().getName()
994                             + " from slave: " + ex.getMessage());
995                 }
996             } else if (isPasv()) {
997                 //_transfer is already set up by doPASV()
998
} else {
999                 return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;
1000            }
1001            if( _transfer == null)throw new NullPointerException JavaDoc();
1002            {
1003                PrintWriter JavaDoc out = conn.getControlWriter();
1004                out.write(new FtpReply(150,
1005                        "File status okay; about to open data connection "
1006                                + (isRetr ? "from " : "to ")
1007                                + _rslave.getName() + ".").toString());
1008                out.flush();
1009            }
1010            TransferStatus status;
1011            //transfer
1012
try {
1013                //TODO ABORtable transfers
1014
if (isRetr) {
1015                    status = _transferFile.sendFile(_transfer, getType(),
1016                            _resumePosition);
1017                } else if (isStor) {
1018                    status = _transferFile.receiveFile(_transfer, getType(),
1019                            _resumePosition);
1020                } else {
1021                    throw new RuntimeException JavaDoc();
1022                }
1023            } catch (RemoteException JavaDoc ex) {
1024                _rslave.handleRemoteException(ex);
1025                if (isStor) {
1026                    _transferFile.delete();
1027                    logger
1028                            .error("RemoteException during transfer, deleting file");
1029                    return new FtpReply(426, "RemoteException, deleting file");
1030                } else {
1031                    logger.error("RemoteException during transfer");
1032                    return new FtpReply(426, "RemoteException during transfer");
1033                }
1034            } catch (FileExistsException ex) {
1035                // slave is unsync'd
1036
logger.warn("Slave is unsynchronized", ex);
1037                return new FtpReply(426,
1038                        "FileExistsException, slave is unsynchronized: "
1039                                + ex.getMessage());
1040            } catch (IOException JavaDoc ex) {
1041                if (ex instanceof TransferFailedException) {
1042                    status = ((TransferFailedException) ex).getStatus();
1043                    conn.getConnectionManager().dispatchFtpEvent(
1044                            new TransferEvent(conn.getUserNull(), eventType,
1045                                    _transferFile, conn.getClientAddress(),
1046                                    _rslave, status.getPeer(), type, false));
1047                    if (isRetr) {
1048                        conn.getUserNull().updateCredits(
1049                                -status.getTransfered());
1050                    }
1051                }
1052                FtpReply reply = null;
1053                if (isStor) {
1054                    _transferFile.delete();
1055                    logger.error("IOException during transfer, deleting file",
1056                            ex);
1057                    reply = new FtpReply(426, "IOException, deleting file");
1058                } else {
1059                    logger.error("IOException during transfer", ex);
1060                    reply = new FtpReply(426, "IOException during transfer");
1061                }
1062                reply.addComment(ex.getLocalizedMessage());
1063                return reply;
1064            }
1065            // TransferThread transferThread = new TransferThread(rslave,
1066
// transfer);
1067
// System.err.println("Calling interruptibleSleepUntilFinished");
1068
// try {
1069
// transferThread.interruptibleSleepUntilFinished();
1070
// } catch (Throwable e1) {
1071
// e1.printStackTrace();
1072
// }
1073
// System.err.println("Finished");
1074
ReplacerEnvironment env = new ReplacerEnvironment();
1075            env.add("bytes", Bytes.formatBytes(status.getTransfered()));
1076            env.add("speed", Bytes.formatBytes(status.getXferSpeed()) + "/s");
1077            env.add("seconds", "" + status.getElapsed() / 1000);
1078            env.add("checksum", Checksum.formatChecksum(status.getChecksum()));
1079            FtpReply response = new FtpReply(226, conn.jprintf(
1080                    DataConnectionHandler.class.getName(), "transfer.complete",
1081                    env));
1082            if (isStor) {
1083                // throws RemoteException
1084
if (_resumePosition == 0) {
1085                    _transferFile.setCheckSum(status.getChecksum());
1086                } else {
1087                    // try {
1088
// checksum = _transferFile.getCheckSumFromSlave();
1089
// } catch (NoAvailableSlaveException e) {
1090
// response.addComment(
1091
// "No available slaves when getting checksum from slave: "
1092
// + e.getMessage());
1093
// logger.warn("", e);
1094
// checksum = 0;
1095
// } catch (IOException e) {
1096
// response.addComment(
1097
// "IO error getting checksum from slave: "
1098
// + e.getMessage());
1099
// logger.warn("", e);
1100
// checksum = 0;
1101
// }
1102
}
1103                _transferFile.setLastModified(System.currentTimeMillis());
1104                _transferFile.setLength(status.getTransfered());
1105                _transferFile.setXfertime(status.getElapsed());
1106            }
1107            boolean zipscript = zipscript(isRetr, isStor, status.getChecksum(),
1108                    response, targetFileName, targetDir);
1109            if (zipscript) {
1110                //transferstatistics
1111
if (isRetr) {
1112                    float ratio = conn.getConfig().getCreditLossRatio(
1113                            _transferFile, conn.getUserNull());
1114                    if (ratio != 0) {
1115                        conn.getUserNull().updateCredits(
1116                                (long) (-status.getTransfered() * ratio));
1117                    }
1118                    conn.getUserNull().updateDownloadedBytes(
1119                            status.getTransfered());
1120                    conn.getUserNull().updateDownloadedMilliseconds(
1121                            status.getElapsed());
1122                    conn.getUserNull().updateDownloadedFiles(1);
1123                } else {
1124                    conn.getUserNull().updateCredits(
1125                            (long) (status.getTransfered() * conn.getConfig()
1126                                    .getCreditCheckRatio(_transferFile,
1127                                            conn.getUserNull())));
1128                    conn.getUserNull().updateUploadedBytes(
1129                            status.getTransfered());
1130                    conn.getUserNull().updateUploadedMilliseconds(
1131                            status.getElapsed());
1132                    conn.getUserNull().updateUploadedFiles(1);
1133                }
1134                try {
1135                    conn.getUserNull().commit();
1136                } catch (UserFileException e) {
1137                    logger.warn("", e);
1138                }
1139            }
1140            //Dispatch for both STOR and RETR
1141
conn.getConnectionManager().dispatchFtpEvent(
1142                    new TransferEvent(conn.getUserNull(), eventType,
1143                            _transferFile, conn.getClientAddress(), _rslave,
1144                            status.getPeer(), getType(), zipscript));
1145            return response;
1146        } finally {
1147            reset();
1148        }
1149    }
1150    public void unload() {
1151        if (isPasv()) {
1152            _portRange.releasePort(_serverSocket.getLocalPort());
1153        }
1154    }
1155    /**
1156     * @param isRetr
1157     * @param isStor
1158     * @param status
1159     * @param response
1160     * @param targetFileName
1161     * @param targetDir
1162     * Returns true if crc check was okay, i.e, if credits should be
1163     * altered
1164     */

1165    private boolean zipscript(boolean isRetr, boolean isStor, long checksum,
1166            FtpReply response, String JavaDoc targetFileName,
1167            LinkedRemoteFileInterface targetDir) {
1168        //zipscript
1169
logger.debug("Running zipscript on file " + targetFileName
1170                + " with CRC of " + checksum);
1171        if (isRetr) {
1172            //compare checksum from transfer to cached checksum
1173
logger.debug("checksum from transfer = " + checksum);
1174            if (checksum != 0) {
1175                response.addComment("Checksum from transfer: "
1176                        + Checksum.formatChecksum(checksum));
1177                long cachedChecksum;
1178                cachedChecksum = _transferFile.getCheckSumCached();
1179                if (cachedChecksum == 0) {
1180                    _transferFile.setCheckSum(checksum);
1181                } else if (cachedChecksum != checksum) {
1182                    response
1183                            .addComment("WARNING: checksum from transfer didn't match cached checksum");
1184                    logger.info("checksum from transfer "
1185                            + Checksum.formatChecksum(checksum)
1186                            + "didn't match cached checksum"
1187                            + Checksum.formatChecksum(cachedChecksum) + " for "
1188                            + _transferFile.toString() + " from slave "
1189                            + _rslave.getName(), new Throwable JavaDoc());
1190                }
1191                //compare checksum from transfer to checksum from sfv
1192
try {
1193                    long sfvChecksum = _transferFile.getParentFileNull()
1194                            .lookupSFVFile().getChecksum(
1195                                    _transferFile.getName());
1196                    if (sfvChecksum == checksum) {
1197                        response
1198                                .addComment("checksum from transfer matched checksum in .sfv");
1199                    } else {
1200                        response
1201                                .addComment("WARNING: checksum from transfer didn't match checksum in .sfv");
1202                    }
1203                } catch (NoAvailableSlaveException e1) {
1204                    response
1205                            .addComment("slave with .sfv offline, checksum not verified");
1206                } catch (FileNotFoundException JavaDoc e1) {
1207                    //continue without verification
1208
} catch (NoSFVEntryException e1) {
1209                    //file not found in .sfv, continue
1210
} catch (IOException JavaDoc e1) {
1211                    logger.info("", e1);
1212                    response.addComment("IO Error reading sfv file: "
1213                            + e1.getMessage());
1214                }
1215            } else { // slave has disabled download crc
1216
//response.addComment("Slave has disabled download checksum");
1217
}
1218        } else if (isStor) {
1219            if (!targetFileName.toLowerCase().endsWith(".sfv")) {
1220                try {
1221                    long sfvChecksum = targetDir.lookupSFVFile().getChecksum(
1222                            targetFileName);
1223                    if (checksum == sfvChecksum) {
1224                        response.addComment("checksum match: SLAVE/SFV:"
1225                                + Long.toHexString(checksum));
1226                    } else if (checksum == 0) {
1227                        response
1228                                .addComment("checksum match: SLAVE/SFV: DISABLED");
1229                    } else {
1230                        response.addComment("checksum mismatch: SLAVE: "
1231                                + Long.toHexString(checksum) + " SFV: "
1232                                + Long.toHexString(sfvChecksum));
1233                        response.addComment(" deleting file");
1234                        response.setMessage("Checksum mismatch, deleting file");
1235                        _transferFile.delete();
1236                        // getUser().updateCredits(
1237
// - ((long) getUser().getRatio() * transferedBytes));
1238
// getUser().updateUploadedBytes(-transferedBytes);
1239
// response.addComment(conn.status());
1240
return false; // don't modify credits
1241
// String badtargetFilename = targetFilename + ".bad";
1242
//
1243
// try {
1244
// LinkedRemoteFile badtargetFile =
1245
// targetDir.getFile(badtargetFilename);
1246
// badtargetFile.delete();
1247
// response.addComment(
1248
// "zipscript - removing "
1249
// + badtargetFilename
1250
// + " to be replaced with new file");
1251
// } catch (FileNotFoundException e2) {
1252
// //good, continue...
1253
// response.addComment(
1254
// "zipscript - checksum mismatch, renaming to "
1255
// + badtargetFilename);
1256
// }
1257
// targetFile.renameTo(targetDir.getPath() +
1258
// badtargetFilename);
1259
}
1260                } catch (NoAvailableSlaveException e) {
1261                    response
1262                            .addComment("zipscript - SFV unavailable, slave(s) with .sfv file is offline");
1263                } catch (NoSFVEntryException e) {
1264                    response.addComment("zipscript - no entry in sfv for file");
1265                } catch (IOException JavaDoc e) {
1266                    response
1267                            .addComment("zipscript - SFV unavailable, IO error: "
1268                                    + e.getMessage());
1269                }
1270            }
1271        }
1272        return true; // modify credits, transfer was okay
1273
}
1274}
Popular Tags