OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [net/] [protocol/] [ftp/] [FTPConnection.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* FTPConnection.java --
2
   Copyright (C) 2003, 2004  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package gnu.java.net.protocol.ftp;
40
 
41
import gnu.java.lang.CPStringBuilder;
42
 
43
import gnu.java.net.CRLFInputStream;
44
import gnu.java.net.CRLFOutputStream;
45
import gnu.java.net.EmptyX509TrustManager;
46
import gnu.java.net.LineInputStream;
47
 
48
import java.io.BufferedInputStream;
49
import java.io.BufferedOutputStream;
50
import java.io.IOException;
51
import java.io.InputStream;
52
import java.io.OutputStream;
53
import java.net.BindException;
54
import java.net.InetAddress;
55
import java.net.InetSocketAddress;
56
import java.net.ProtocolException;
57
import java.net.Socket;
58
import java.net.UnknownHostException;
59
import java.security.GeneralSecurityException;
60
import java.util.ArrayList;
61
import java.util.List;
62
 
63
import javax.net.ssl.SSLContext;
64
import javax.net.ssl.SSLSocket;
65
import javax.net.ssl.SSLSocketFactory;
66
import javax.net.ssl.TrustManager;
67
 
68
/**
69
 * An FTP client connection, or PI.
70
 * This implements RFC 959, with the following exceptions:
71
 * <ul>
72
 * <li>STAT, HELP, SITE, SMNT, and ACCT commands are not supported.</li>
73
 * <li>the TYPE command does not allow alternatives to the default bytesize
74
 * (Non-print), and local bytesize is not supported.</li>
75
 * </ul>
76
 *
77
 * @author Chris Burdess (dog@gnu.org)
78
 */
79
public class FTPConnection
80
{
81
 
82
  /**
83
   * The default FTP transmission control port.
84
   */
85
  public static final int FTP_PORT = 21;
86
 
87
  /**
88
   * The FTP data port.
89
   */
90
  public static final int FTP_DATA_PORT = 20;
91
 
92
  // -- FTP vocabulary --
93
  protected static final String USER = "USER";
94
  protected static final String PASS = "PASS";
95
  protected static final String ACCT = "ACCT";
96
  protected static final String CWD = "CWD";
97
  protected static final String CDUP = "CDUP";
98
  protected static final String SMNT = "SMNT";
99
  protected static final String REIN = "REIN";
100
  protected static final String QUIT = "QUIT";
101
 
102
  protected static final String PORT = "PORT";
103
  protected static final String PASV = "PASV";
104
  protected static final String TYPE = "TYPE";
105
  protected static final String STRU = "STRU";
106
  protected static final String MODE = "MODE";
107
 
108
  protected static final String RETR = "RETR";
109
  protected static final String STOR = "STOR";
110
  protected static final String STOU = "STOU";
111
  protected static final String APPE = "APPE";
112
  protected static final String ALLO = "ALLO";
113
  protected static final String REST = "REST";
114
  protected static final String RNFR = "RNFR";
115
  protected static final String RNTO = "RNTO";
116
  protected static final String ABOR = "ABOR";
117
  protected static final String DELE = "DELE";
118
  protected static final String RMD = "RMD";
119
  protected static final String MKD = "MKD";
120
  protected static final String PWD = "PWD";
121
  protected static final String LIST = "LIST";
122
  protected static final String NLST = "NLST";
123
  protected static final String SITE = "SITE";
124
  protected static final String SYST = "SYST";
125
  protected static final String STAT = "STAT";
126
  protected static final String HELP = "HELP";
127
  protected static final String NOOP = "NOOP";
128
 
129
  protected static final String AUTH = "AUTH";
130
  protected static final String PBSZ = "PBSZ";
131
  protected static final String PROT = "PROT";
132
  protected static final String CCC = "CCC";
133
  protected static final String TLS = "TLS";
134
 
135
  public static final int TYPE_ASCII = 1;
136
  public static final int TYPE_EBCDIC = 2;
137
  public static final int TYPE_BINARY = 3;
138
 
139
  public static final int STRUCTURE_FILE = 1;
140
  public static final int STRUCTURE_RECORD = 2;
141
  public static final int STRUCTURE_PAGE = 3;
142
 
143
  public static final int MODE_STREAM = 1;
144
  public static final int MODE_BLOCK = 2;
145
  public static final int MODE_COMPRESSED = 3;
146
 
147
  // -- Telnet constants --
148
  private static final String US_ASCII = "US-ASCII";
149
 
150
  /**
151
   * The socket used to communicate with the server.
152
   */
153
  protected Socket socket;
154
 
155
  /**
156
   * The socket input stream.
157
   */
158
  protected LineInputStream in;
159
 
160
  /**
161
   * The socket output stream.
162
   */
163
  protected CRLFOutputStream out;
164
 
165
  /**
166
   * The timeout when attempting to connect a socket.
167
   */
168
  protected int connectionTimeout;
169
 
170
  /**
171
   * The read timeout on sockets.
172
   */
173
  protected int timeout;
174
 
175
  /**
176
   * If true, print debugging information.
177
   */
178
  protected boolean debug;
179
 
180
  /**
181
   * The current data transfer process in use by this connection.
182
   */
183
  protected DTP dtp;
184
 
185
  /**
186
   * The current representation type.
187
   */
188
  protected int representationType = TYPE_ASCII;
189
 
190
  /**
191
   * The current file structure type.
192
   */
193
  protected int fileStructure = STRUCTURE_FILE;
194
 
195
  /**
196
   * The current transfer mode.
197
   */
198
  protected int transferMode = MODE_STREAM;
199
 
200
  /**
201
   * If true, use passive mode.
202
   */
203
  protected boolean passive = false;
204
 
205
  /**
206
   * Creates a new connection to the server using the default port.
207
   * @param hostname the hostname of the server to connect to
208
   */
209
  public FTPConnection(String hostname)
210
    throws UnknownHostException, IOException
211
  {
212
    this(hostname, -1, 0, 0, false);
213
  }
214
 
215
  /**
216
   * Creates a new connection to the server.
217
   * @param hostname the hostname of the server to connect to
218
   * @param port the port to connect to(if &lt;=0, use default port)
219
   */
220
  public FTPConnection(String hostname, int port)
221
    throws UnknownHostException, IOException
222
  {
223
    this(hostname, port, 0, 0, false);
224
  }
225
 
226
  /**
227
   * Creates a new connection to the server.
228
   * @param hostname the hostname of the server to connect to
229
   * @param port the port to connect to(if &lt;=0, use default port)
230
   * @param connectionTimeout the connection timeout, in milliseconds
231
   * @param timeout the I/O timeout, in milliseconds
232
   * @param debug print debugging information
233
   */
234
  public FTPConnection(String hostname, int port,
235
                        int connectionTimeout, int timeout, boolean debug)
236
    throws UnknownHostException, IOException
237
  {
238
    this.connectionTimeout = connectionTimeout;
239
    this.timeout = timeout;
240
    this.debug = debug;
241
    if (port <= 0)
242
      {
243
        port = FTP_PORT;
244
      }
245
 
246
    // Set up socket
247
    socket = new Socket();
248
    InetSocketAddress address = new InetSocketAddress(hostname, port);
249
    if (connectionTimeout > 0)
250
      {
251
        socket.connect(address, connectionTimeout);
252
      }
253
    else
254
      {
255
        socket.connect(address);
256
      }
257
    if (timeout > 0)
258
      {
259
        socket.setSoTimeout(timeout);
260
      }
261
 
262
    InputStream in = socket.getInputStream();
263
    in = new BufferedInputStream(in);
264
    in = new CRLFInputStream(in);
265
    this.in = new LineInputStream(in);
266
    OutputStream out = socket.getOutputStream();
267
    out = new BufferedOutputStream(out);
268
    this.out = new CRLFOutputStream(out);
269
 
270
    // Read greeting
271
    FTPResponse response = getResponse();
272
    switch (response.getCode())
273
      {
274
      case 220:                  // hello
275
        break;
276
      default:
277
        throw new FTPException(response);
278
      }
279
  }
280
 
281
  /**
282
   * Authenticate using the specified username and password.
283
   * If the username suffices for the server, the password will not be used
284
   * and may be null.
285
   * @param username the username
286
   * @param password the optional password
287
   * @return true on success, false otherwise
288
   */
289
  public boolean authenticate(String username, String password)
290
    throws IOException
291
  {
292
    String cmd = USER + ' ' + username;
293
    send(cmd);
294
    FTPResponse response = getResponse();
295
    switch (response.getCode())
296
      {
297
      case 230:                  // User logged in
298
        return true;
299
      case 331:                 // User name okay, need password
300
        break;
301
      case 332:                 // Need account for login
302
      case 530:                 // No such user
303
        return false;
304
      default:
305
        throw new FTPException(response);
306
      }
307
    cmd = PASS + ' ' + password;
308
    send(cmd);
309
    response = getResponse();
310
    switch (response.getCode())
311
      {
312
      case 230:                  // User logged in
313
      case 202:                  // Superfluous
314
        return true;
315
      case 332:                  // Need account for login
316
      case 530:                  // Bad password
317
        return false;
318
      default:
319
        throw new FTPException(response);
320
      }
321
  }
322
 
323
  /**
324
   * Negotiates TLS over the current connection.
325
   * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
326
   * @param confidential whether to provide confidentiality for the
327
   * connection
328
   */
329
  public boolean starttls(boolean confidential)
330
    throws IOException
331
  {
332
    return starttls(confidential, new EmptyX509TrustManager());
333
  }
334
 
335
  /**
336
   * Negotiates TLS over the current connection.
337
   * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
338
   * @param confidential whether to provide confidentiality for the
339
   * connection
340
   * @param tm the trust manager used to validate the server certificate.
341
   */
342
  public boolean starttls(boolean confidential, TrustManager tm)
343
    throws IOException
344
  {
345
    try
346
      {
347
        // Use SSLSocketFactory to negotiate a TLS session and wrap the
348
        // current socket.
349
        SSLContext context = SSLContext.getInstance("TLS");
350
        // We don't require strong validation of the server certificate
351
        TrustManager[] trust = new TrustManager[] { tm };
352
        context.init(null, trust, null);
353
        SSLSocketFactory factory = context.getSocketFactory();
354
 
355
        send(AUTH + ' ' + TLS);
356
        FTPResponse response = getResponse();
357
        switch (response.getCode())
358
          {
359
          case 500:
360
          case 502:
361
          case 504:
362
          case 534:
363
          case 431:
364
            return false;
365
          case 234:
366
            break;
367
          default:
368
            throw new FTPException(response);
369
          }
370
 
371
        String hostname = socket.getInetAddress().getHostName();
372
        int port = socket.getPort();
373
        SSLSocket ss =
374
         (SSLSocket) factory.createSocket(socket, hostname, port, true);
375
        String[] protocols = { "TLSv1", "SSLv3" };
376
        ss.setEnabledProtocols(protocols);
377
        ss.setUseClientMode(true);
378
        ss.startHandshake();
379
 
380
        // PBSZ:PROT sequence
381
        send(PBSZ + ' ' + Integer.MAX_VALUE);
382
        response = getResponse();
383
        switch (response.getCode())
384
          {
385
          case 501: // syntax error
386
          case 503: // not authenticated
387
            return false;
388
          case 200:
389
            break;
390
          default:
391
            throw new FTPException(response);
392
          }
393
        send(PROT + ' ' +(confidential ? 'P' : 'C'));
394
        response = getResponse();
395
        switch (response.getCode())
396
          {
397
          case 503: // not authenticated
398
          case 504: // invalid level
399
          case 536: // level not supported
400
            return false;
401
          case 200:
402
            break;
403
          default:
404
            throw new FTPException(response);
405
          }
406
 
407
        if (confidential)
408
          {
409
            // Set up streams
410
            InputStream in = ss.getInputStream();
411
            in = new BufferedInputStream(in);
412
            in = new CRLFInputStream(in);
413
            this.in = new LineInputStream(in);
414
            OutputStream out = ss.getOutputStream();
415
            out = new BufferedOutputStream(out);
416
            this.out = new CRLFOutputStream(out);
417
          }
418
        return true;
419
      }
420
    catch (GeneralSecurityException e)
421
      {
422
        return false;
423
      }
424
  }
425
 
426
  /**
427
   * Changes directory to the specified path.
428
   * @param path an absolute or relative pathname
429
   * @return true on success, false if the specified path does not exist
430
   */
431
  public boolean changeWorkingDirectory(String path)
432
    throws IOException
433
  {
434
    // Do nothing if the path is empty.
435
    if (path.length() == 0)
436
      return true;
437
    String cmd = CWD + ' ' + path;
438
    send(cmd);
439
    FTPResponse response = getResponse();
440
    switch (response.getCode())
441
      {
442
      case 250:
443
        return true;
444
      case 550:
445
        return false;
446
      default:
447
        throw new FTPException(response);
448
      }
449
  }
450
 
451
  /**
452
   * Changes directory to the parent of the current working directory.
453
   * @return true on success, false otherwise
454
   */
455
  public boolean changeToParentDirectory()
456
    throws IOException
457
  {
458
    send(CDUP);
459
    FTPResponse response = getResponse();
460
    switch (response.getCode())
461
      {
462
      case 250:
463
        return true;
464
      case 550:
465
        return false;
466
      default:
467
        throw new FTPException(response);
468
      }
469
  }
470
 
471
  /**
472
   * Terminates an authenticated login.
473
   * If file transfer is in progress, it remains active for result response
474
   * only.
475
   */
476
  public void reinitialize()
477
    throws IOException
478
  {
479
    send(REIN);
480
    FTPResponse response = getResponse();
481
    switch (response.getCode())
482
      {
483
      case 220:
484
        if (dtp != null)
485
          {
486
            dtp.complete();
487
            dtp = null;
488
          }
489
        break;
490
      default:
491
        throw new FTPException(response);
492
      }
493
  }
494
 
495
  /**
496
   * Terminates the control connection.
497
   * The file transfer connection remains open for result response only.
498
   * This connection is invalid and no further commands may be issued.
499
   */
500
  public void logout()
501
    throws IOException
502
  {
503
    send(QUIT);
504
    try
505
      {
506
        getResponse();            // not required
507
      }
508
    catch (IOException e)
509
      {
510
      }
511
    if (dtp != null)
512
      {
513
        dtp.complete();
514
        dtp = null;
515
      }
516
    try
517
      {
518
        socket.close();
519
      }
520
    catch (IOException e)
521
      {
522
      }
523
  }
524
 
525
  /**
526
   * Initialise the data transfer process.
527
   */
528
  protected void initialiseDTP()
529
    throws IOException
530
  {
531
    if (dtp != null)
532
      {
533
        dtp.complete();
534
        dtp = null;
535
      }
536
 
537
    InetAddress localhost = socket.getLocalAddress();
538
    if (passive)
539
      {
540
        send(PASV);
541
        FTPResponse response = getResponse();
542
        switch (response.getCode())
543
          {
544
          case 227:
545
            String message = response.getMessage();
546
            try
547
              {
548
                int start = message.indexOf(',');
549
                char c = message.charAt(start - 1);
550
                while (c >= 0x30 && c <= 0x39)
551
                  {
552
                    c = message.charAt((--start) - 1);
553
                  }
554
                int mid1 = start;
555
                for (int i = 0; i < 4; i++)
556
                  {
557
                    mid1 = message.indexOf(',', mid1 + 1);
558
                  }
559
                int mid2 = message.indexOf(',', mid1 + 1);
560
                if (mid1 == -1 || mid2 < mid1)
561
                  {
562
                    throw new ProtocolException("Malformed 227: " +
563
                                                 message);
564
                  }
565
                int end = mid2;
566
                c = message.charAt(end + 1);
567
                while (c >= 0x30 && c <= 0x39)
568
                  {
569
                    c = message.charAt((++end) + 1);
570
                  }
571
 
572
                String address =
573
                  message.substring(start, mid1).replace(',', '.');
574
                int port_hi =
575
                  Integer.parseInt(message.substring(mid1 + 1, mid2));
576
                int port_lo =
577
                  Integer.parseInt(message.substring(mid2 + 1, end + 1));
578
                int port = (port_hi << 8) | port_lo;
579
 
580
                /*System.out.println("Entering passive mode: " + address +
581
                  ":" + port);*/
582
                dtp = new PassiveModeDTP(address, port, localhost,
583
                                          connectionTimeout, timeout);
584
                break;
585
              }
586
            catch (ArrayIndexOutOfBoundsException e)
587
              {
588
                throw new ProtocolException(e.getMessage() + ": " +
589
                                             message);
590
              }
591
            catch (NumberFormatException e)
592
              {
593
                throw new ProtocolException(e.getMessage() + ": " +
594
                                             message);
595
              }
596
          default:
597
            throw new FTPException(response);
598
          }
599
      }
600
    else
601
      {
602
        // Get the local port
603
        int port = socket.getLocalPort() + 1;
604
        int tries = 0;
605
        // Bind the active mode DTP
606
        while (dtp == null)
607
          {
608
            try
609
              {
610
                dtp = new ActiveModeDTP(localhost, port,
611
                                         connectionTimeout, timeout);
612
                /*System.out.println("Listening on: " + port);*/
613
              }
614
            catch (BindException e)
615
              {
616
                port++;
617
                tries++;
618
                if (tries > 9)
619
                  {
620
                    throw e;
621
                  }
622
              }
623
          }
624
 
625
        // Send PORT command
626
        CPStringBuilder buf = new CPStringBuilder(PORT);
627
        buf.append(' ');
628
        // Construct the address/port string form
629
        byte[] address = localhost.getAddress();
630
        for (int i = 0; i < address.length; i++)
631
          {
632
            int a =(int) address[i];
633
            if (a < 0)
634
              {
635
                a += 0x100;
636
              }
637
            buf.append(a);
638
            buf.append(',');
639
          }
640
        int port_hi =(port & 0xff00) >> 8;
641
        int port_lo =(port & 0x00ff);
642
        buf.append(port_hi);
643
        buf.append(',');
644
        buf.append(port_lo);
645
        send(buf.toString());
646
        // Get response
647
        FTPResponse response = getResponse();
648
        switch (response.getCode())
649
          {
650
          case 200:                // OK
651
            break;
652
          default:
653
            dtp.abort();
654
            dtp = null;
655
            throw new FTPException(response);
656
          }
657
      }
658
    dtp.setTransferMode(transferMode);
659
  }
660
 
661
  /**
662
   * Set passive mode.
663
   * @param flag true if we should use passive mode, false otherwise
664
   */
665
  public void setPassive(boolean flag)
666
    throws IOException
667
  {
668
    if (passive != flag)
669
      {
670
        passive = flag;
671
        initialiseDTP();
672
      }
673
  }
674
 
675
  /**
676
   * Returns the current representation type of the transfer data.
677
   * @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
678
   */
679
  public int getRepresentationType()
680
  {
681
    return representationType;
682
  }
683
 
684
  /**
685
   * Sets the desired representation type of the transfer data.
686
   * @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
687
   */
688
  public void setRepresentationType(int type)
689
    throws IOException
690
  {
691
    CPStringBuilder buf = new CPStringBuilder(TYPE);
692
    buf.append(' ');
693
    switch (type)
694
      {
695
      case TYPE_ASCII:
696
        buf.append('A');
697
        break;
698
      case TYPE_EBCDIC:
699
        buf.append('E');
700
        break;
701
      case TYPE_BINARY:
702
        buf.append('I');
703
        break;
704
      default:
705
        throw new IllegalArgumentException(Integer.toString(type));
706
      }
707
    //buf.append(' ');
708
    //buf.append('N');
709
    send(buf.toString());
710
    FTPResponse response = getResponse();
711
    switch (response.getCode())
712
      {
713
      case 200:
714
        representationType = type;
715
        break;
716
      default:
717
        throw new FTPException(response);
718
      }
719
  }
720
 
721
  /**
722
   * Returns the current file structure type.
723
   * @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
724
   */
725
  public int getFileStructure()
726
  {
727
    return fileStructure;
728
  }
729
 
730
  /**
731
   * Sets the desired file structure type.
732
   * @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
733
   */
734
  public void setFileStructure(int structure)
735
    throws IOException
736
  {
737
    CPStringBuilder buf = new CPStringBuilder(STRU);
738
    buf.append(' ');
739
    switch (structure)
740
      {
741
      case STRUCTURE_FILE:
742
        buf.append('F');
743
        break;
744
      case STRUCTURE_RECORD:
745
        buf.append('R');
746
        break;
747
      case STRUCTURE_PAGE:
748
        buf.append('P');
749
        break;
750
      default:
751
        throw new IllegalArgumentException(Integer.toString(structure));
752
      }
753
    send(buf.toString());
754
    FTPResponse response = getResponse();
755
    switch (response.getCode())
756
      {
757
      case 200:
758
        fileStructure = structure;
759
        break;
760
      default:
761
        throw new FTPException(response);
762
      }
763
  }
764
 
765
  /**
766
   * Returns the current transfer mode.
767
   * @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
768
   */
769
  public int getTransferMode()
770
  {
771
    return transferMode;
772
  }
773
 
774
  /**
775
   * Sets the desired transfer mode.
776
   * @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
777
   */
778
  public void setTransferMode(int mode)
779
    throws IOException
780
  {
781
    CPStringBuilder buf = new CPStringBuilder(MODE);
782
    buf.append(' ');
783
    switch (mode)
784
      {
785
      case MODE_STREAM:
786
        buf.append('S');
787
        break;
788
      case MODE_BLOCK:
789
        buf.append('B');
790
        break;
791
      case MODE_COMPRESSED:
792
        buf.append('C');
793
        break;
794
      default:
795
        throw new IllegalArgumentException(Integer.toString(mode));
796
      }
797
    send(buf.toString());
798
    FTPResponse response = getResponse();
799
    switch (response.getCode())
800
      {
801
      case 200:
802
        transferMode = mode;
803
        if (dtp != null)
804
          {
805
            dtp.setTransferMode(mode);
806
          }
807
        break;
808
      default:
809
        throw new FTPException(response);
810
      }
811
  }
812
 
813
  /**
814
   * Retrieves the specified file.
815
   * @param filename the filename of the file to retrieve
816
   * @return an InputStream containing the file content
817
   */
818
  public InputStream retrieve(String filename)
819
    throws IOException
820
  {
821
    if (dtp == null || transferMode == MODE_STREAM)
822
      {
823
        initialiseDTP();
824
      }
825
    /*
826
       int size = -1;
827
       String cmd = SIZE + ' ' + filename;
828
       send(cmd);
829
       FTPResponse response = getResponse();
830
       switch (response.getCode())
831
       {
832
       case 213:
833
       size = Integer.parseInt(response.getMessage());
834
       break;
835
       case 550: // File not found
836
       default:
837
       throw new FTPException(response);
838
       }
839
     */
840
    String cmd = RETR + ' ' + filename;
841
    send(cmd);
842
    FTPResponse response = getResponse();
843
    switch (response.getCode())
844
      {
845
      case 125:                  // Data connection already open; transfer starting
846
      case 150:                  // File status okay; about to open data connection
847
        return dtp.getInputStream();
848
      default:
849
        throw new FTPException(response);
850
      }
851
  }
852
 
853
  /**
854
   * Returns a stream for uploading a file.
855
   * If a file with the same filename already exists on the server, it will
856
   * be overwritten.
857
   * @param filename the name of the file to save the content as
858
   * @return an OutputStream to write the file data to
859
   */
860
  public OutputStream store(String filename)
861
    throws IOException
862
  {
863
    if (dtp == null || transferMode == MODE_STREAM)
864
      {
865
        initialiseDTP();
866
      }
867
    String cmd = STOR + ' ' + filename;
868
    send(cmd);
869
    FTPResponse response = getResponse();
870
    switch (response.getCode())
871
      {
872
      case 125:                  // Data connection already open; transfer starting
873
      case 150:                  // File status okay; about to open data connection
874
        return dtp.getOutputStream();
875
      default:
876
        throw new FTPException(response);
877
      }
878
  }
879
 
880
  /**
881
   * Returns a stream for uploading a file.
882
   * If a file with the same filename already exists on the server, the
883
   * content specified will be appended to the existing file.
884
   * @param filename the name of the file to save the content as
885
   * @return an OutputStream to write the file data to
886
   */
887
  public OutputStream append(String filename)
888
    throws IOException
889
  {
890
    if (dtp == null || transferMode == MODE_STREAM)
891
      {
892
        initialiseDTP();
893
      }
894
    String cmd = APPE + ' ' + filename;
895
    send(cmd);
896
    FTPResponse response = getResponse();
897
    switch (response.getCode())
898
      {
899
      case 125:                  // Data connection already open; transfer starting
900
      case 150:                  // File status okay; about to open data connection
901
        return dtp.getOutputStream();
902
      default:
903
        throw new FTPException(response);
904
      }
905
  }
906
 
907
  /**
908
   * This command may be required by some servers to reserve sufficient
909
   * storage to accommodate the new file to be transferred.
910
   * It should be immediately followed by a <code>store</code> or
911
   * <code>append</code>.
912
   * @param size the number of bytes of storage to allocate
913
   */
914
  public void allocate(long size)
915
    throws IOException
916
  {
917
    String cmd = ALLO + ' ' + size;
918
    send(cmd);
919
    FTPResponse response = getResponse();
920
    switch (response.getCode())
921
      {
922
      case 200:                  // OK
923
      case 202:                  // Superfluous
924
        break;
925
      default:
926
        throw new FTPException(response);
927
      }
928
  }
929
 
930
  /**
931
   * Renames a file.
932
   * @param oldName the current name of the file
933
   * @param newName the new name
934
   * @return true if successful, false otherwise
935
   */
936
  public boolean rename(String oldName, String newName)
937
    throws IOException
938
  {
939
    String cmd = RNFR + ' ' + oldName;
940
    send(cmd);
941
    FTPResponse response = getResponse();
942
    switch (response.getCode())
943
      {
944
      case 450:                  // File unavailable
945
      case 550:                  // File not found
946
        return false;
947
      case 350:                 // Pending
948
        break;
949
      default:
950
        throw new FTPException(response);
951
      }
952
    cmd = RNTO + ' ' + newName;
953
    send(cmd);
954
    response = getResponse();
955
    switch (response.getCode())
956
      {
957
      case 250:                  // OK
958
        return true;
959
      case 450:
960
      case 550:
961
        return false;
962
      default:
963
        throw new FTPException(response);
964
      }
965
  }
966
 
967
  /**
968
   * Aborts the transfer in progress.
969
   * @return true if a transfer was in progress, false otherwise
970
   */
971
  public boolean abort()
972
    throws IOException
973
  {
974
    send(ABOR);
975
    FTPResponse response = getResponse();
976
    // Abort client DTP
977
    if (dtp != null)
978
      {
979
        dtp.abort();
980
      }
981
    switch (response.getCode())
982
      {
983
      case 226:                  // successful abort
984
        return false;
985
      case 426:                 // interrupted
986
        response = getResponse();
987
        if (response.getCode() == 226)
988
          {
989
            return true;
990
          }
991
        // Otherwise fall through to throw exception
992
      default:
993
        throw new FTPException(response);
994
      }
995
  }
996
 
997
  /**
998
   * Causes the file specified to be deleted at the server site.
999
   * @param filename the file to delete
1000
   */
1001
  public boolean delete(String filename)
1002
    throws IOException
1003
  {
1004
    String cmd = DELE + ' ' + filename;
1005
    send(cmd);
1006
    FTPResponse response = getResponse();
1007
    switch (response.getCode())
1008
      {
1009
      case 250:                  // OK
1010
        return true;
1011
      case 450:                 // File unavailable
1012
      case 550:                 // File not found
1013
        return false;
1014
      default:
1015
        throw new FTPException(response);
1016
      }
1017
  }
1018
 
1019
  /**
1020
   * Causes the directory specified to be deleted.
1021
   * This may be an absolute or relative pathname.
1022
   * @param pathname the directory to delete
1023
   */
1024
  public boolean removeDirectory(String pathname)
1025
    throws IOException
1026
  {
1027
    String cmd = RMD + ' ' + pathname;
1028
    send(cmd);
1029
    FTPResponse response = getResponse();
1030
    switch (response.getCode())
1031
      {
1032
      case 250:                  // OK
1033
        return true;
1034
      case 550:                 // File not found
1035
        return false;
1036
      default:
1037
        throw new FTPException(response);
1038
      }
1039
  }
1040
 
1041
  /**
1042
   * Causes the directory specified to be created at the server site.
1043
   * This may be an absolute or relative pathname.
1044
   * @param pathname the directory to create
1045
   */
1046
  public boolean makeDirectory(String pathname)
1047
    throws IOException
1048
  {
1049
    String cmd = MKD + ' ' + pathname;
1050
    send(cmd);
1051
    FTPResponse response = getResponse();
1052
    switch (response.getCode())
1053
      {
1054
      case 257:                  // Directory created
1055
        return true;
1056
      case 550:                 // File not found
1057
        return false;
1058
      default:
1059
        throw new FTPException(response);
1060
      }
1061
  }
1062
 
1063
  /**
1064
   * Returns the current working directory.
1065
   */
1066
  public String getWorkingDirectory()
1067
    throws IOException
1068
  {
1069
    send(PWD);
1070
    FTPResponse response = getResponse();
1071
    switch (response.getCode())
1072
      {
1073
      case 257:
1074
        String message = response.getMessage();
1075
        if (message.charAt(0) == '"')
1076
          {
1077
            int end = message.indexOf('"', 1);
1078
            if (end == -1)
1079
              {
1080
                throw new ProtocolException(message);
1081
              }
1082
            return message.substring(1, end);
1083
          }
1084
        else
1085
          {
1086
            int end = message.indexOf(' ');
1087
            if (end == -1)
1088
              {
1089
                return message;
1090
              }
1091
            else
1092
              {
1093
                return message.substring(0, end);
1094
              }
1095
          }
1096
      default:
1097
        throw new FTPException(response);
1098
      }
1099
  }
1100
 
1101
  /**
1102
   * Returns a listing of information about the specified pathname.
1103
   * If the pathname specifies a directory or other group of files, the
1104
   * server should transfer a list of files in the specified directory.
1105
   * If the pathname specifies a file then the server should send current
1106
   * information on the file.  A null argument implies the user's
1107
   * current working or default directory.
1108
   * @param pathname the context pathname, or null
1109
   */
1110
  public InputStream list(String pathname)
1111
    throws IOException
1112
  {
1113
    if (dtp == null || transferMode == MODE_STREAM)
1114
      {
1115
        initialiseDTP();
1116
      }
1117
    if (pathname == null)
1118
      {
1119
        send(LIST);
1120
      }
1121
    else
1122
      {
1123
        String cmd = LIST + ' ' + pathname;
1124
        send(cmd);
1125
      }
1126
    FTPResponse response = getResponse();
1127
    switch (response.getCode())
1128
      {
1129
      case 125:                  // Data connection already open; transfer starting
1130
      case 150:                  // File status okay; about to open data connection
1131
        return dtp.getInputStream();
1132
      default:
1133
        throw new FTPException(response);
1134
      }
1135
  }
1136
 
1137
  /**
1138
   * Returns a directory listing. The pathname should specify a
1139
   * directory or other system-specific file group descriptor; a null
1140
   * argument implies the user's current working or default directory.
1141
   * @param pathname the directory pathname, or null
1142
   * @return a list of filenames(strings)
1143
   */
1144
  public List<String> nameList(String pathname)
1145
    throws IOException
1146
  {
1147
    if (dtp == null || transferMode == MODE_STREAM)
1148
      {
1149
        initialiseDTP();
1150
      }
1151
    if (pathname == null)
1152
      {
1153
        send(NLST);
1154
      }
1155
    else
1156
      {
1157
        String cmd = NLST + ' ' + pathname;
1158
        send(cmd);
1159
      }
1160
    FTPResponse response = getResponse();
1161
    switch (response.getCode())
1162
      {
1163
      case 125:                  // Data connection already open; transfer starting
1164
      case 150:                  // File status okay; about to open data connection
1165
        InputStream in = dtp.getInputStream();
1166
        in = new BufferedInputStream(in);
1167
        in = new CRLFInputStream(in);     // TODO ensure that TYPE is correct
1168
        LineInputStream li = new LineInputStream(in);
1169
        ArrayList<String> ret = new ArrayList<String>();
1170
        for (String line = li.readLine();
1171
             line != null;
1172
             line = li.readLine())
1173
          {
1174
            ret.add(line);
1175
          }
1176
        li.close();
1177
        return ret;
1178
      default:
1179
        throw new FTPException(response);
1180
      }
1181
  }
1182
 
1183
  /**
1184
   * Returns the type of operating system at the server.
1185
   */
1186
  public String system()
1187
    throws IOException
1188
  {
1189
    send(SYST);
1190
    FTPResponse response = getResponse();
1191
    switch (response.getCode())
1192
      {
1193
      case 215:
1194
        String message = response.getMessage();
1195
        int end = message.indexOf(' ');
1196
        if (end == -1)
1197
          {
1198
            return message;
1199
          }
1200
        else
1201
          {
1202
            return message.substring(0, end);
1203
          }
1204
      default:
1205
        throw new FTPException(response);
1206
      }
1207
  }
1208
 
1209
  /**
1210
   * Does nothing.
1211
   * This method can be used to ensure that the connection does not time
1212
   * out.
1213
   */
1214
  public void noop()
1215
    throws IOException
1216
  {
1217
    send(NOOP);
1218
    FTPResponse response = getResponse();
1219
    switch (response.getCode())
1220
      {
1221
      case 200:
1222
        break;
1223
      default:
1224
        throw new FTPException(response);
1225
      }
1226
  }
1227
 
1228
  // -- I/O --
1229
 
1230
  /**
1231
   * Sends the specified command line to the server.
1232
   * The CRLF sequence is automatically appended.
1233
   * @param cmd the command line to send
1234
   */
1235
  protected void send(String cmd)
1236
    throws IOException
1237
  {
1238
    byte[] data = cmd.getBytes(US_ASCII);
1239
    out.write(data);
1240
    out.writeln();
1241
    out.flush();
1242
  }
1243
 
1244
  /**
1245
   * Reads the next response from the server.
1246
   * If the server sends the "transfer complete" code, this is handled here,
1247
   * and the next response is passed to the caller.
1248
   */
1249
  protected FTPResponse getResponse()
1250
    throws IOException
1251
  {
1252
    FTPResponse response = readResponse();
1253
    if (response.getCode() == 226)
1254
      {
1255
        if (dtp != null)
1256
          {
1257
            dtp.transferComplete();
1258
          }
1259
        response = readResponse();
1260
      }
1261
    return response;
1262
  }
1263
 
1264
  /**
1265
   * Reads and parses the next response from the server.
1266
   */
1267
  protected FTPResponse readResponse()
1268
    throws IOException
1269
  {
1270
    String line = in.readLine();
1271
    if (line == null)
1272
      {
1273
        throw new ProtocolException( "EOF");
1274
      }
1275
    if (line.length() < 4)
1276
      {
1277
        throw new ProtocolException(line);
1278
      }
1279
    int code = parseCode(line);
1280
    if (code == -1)
1281
      {
1282
        throw new ProtocolException(line);
1283
      }
1284
    char c = line.charAt(3);
1285
    if (c == ' ')
1286
      {
1287
        return new FTPResponse(code, line.substring(4));
1288
      }
1289
    else if (c == '-')
1290
      {
1291
        CPStringBuilder buf = new CPStringBuilder(line.substring(4));
1292
        buf.append('\n');
1293
        while(true)
1294
          {
1295
            line = in.readLine();
1296
            if (line == null)
1297
              {
1298
                throw new ProtocolException("EOF");
1299
              }
1300
            if (line.length() >= 4 &&
1301
                line.charAt(3) == ' ' &&
1302
                parseCode(line) == code)
1303
              {
1304
                return new FTPResponse(code, line.substring(4),
1305
                                        buf.toString());
1306
              }
1307
            else
1308
              {
1309
                buf.append(line);
1310
                buf.append('\n');
1311
              }
1312
          }
1313
      }
1314
    else
1315
      {
1316
        throw new ProtocolException(line);
1317
      }
1318
  }
1319
 
1320
  /*
1321
   * Parses the 3-digit numeric code at the beginning of the given line.
1322
   * Returns -1 on failure.
1323
   */
1324
  static final int parseCode(String line)
1325
  {
1326
    char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) };
1327
    int ret = 0;
1328
    for (int i = 0; i < 3; i++)
1329
      {
1330
        int digit =((int) c[i]) - 0x30;
1331
        if (digit < 0 || digit > 9)
1332
          {
1333
            return -1;
1334
          }
1335
        // Computing integer powers is way too expensive in Java!
1336
        switch (i)
1337
          {
1338
          case 0:
1339
            ret +=(100 * digit);
1340
            break;
1341
          case 1:
1342
            ret +=(10 * digit);
1343
            break;
1344
          case 2:
1345
            ret += digit;
1346
            break;
1347
          }
1348
      }
1349
    return ret;
1350
  }
1351
 
1352
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.