VMSFTPEntryParser.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.net.ftp.parser;

  18. import java.io.BufferedReader;
  19. import java.io.IOException;
  20. import java.text.ParseException;
  21. import java.util.StringTokenizer;

  22. import org.apache.commons.net.ftp.FTPClientConfig;
  23. import org.apache.commons.net.ftp.FTPFile;

  24. /**
  25.  * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. This is a sample of VMS LIST output
  26.  *
  27.  * <pre>
  28.  *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
  29.  *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
  30.  *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
  31.  * </pre>
  32.  * <p>
  33.  * Note: VMSFTPEntryParser can only be instantiated through the DefaultFTPParserFactory by class name. It will not be chosen by the autodetection scheme.
  34.  * </p>
  35.  *
  36.  * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
  37.  * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
  38.  */
  39. public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {

  40.     private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; // 9-NOV-2001 12:30:24

  41.     /**
  42.      * this is the regular expression used by this parser.
  43.      */
  44.     private static final String REGEX = "(.*?;[0-9]+)\\s*" // 1 file and version
  45.             + "(\\d+)(?:/\\d+)?\\s*" // 2 size/allocated
  46.             + "(\\S+)\\s+(\\S+)\\s+" // 3+4 date and time
  47.             + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" // 5(6,7,8) owner
  48.             + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; // 9,10,11 Permissions (O,G,W)
  49.     // TODO - perhaps restrict permissions to [RWED]* ?

  50.     /**
  51.      * Constructor for a VMSFTPEntryParser object.
  52.      *
  53.      * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen under normal conditions. If the exception is seen,
  54.      *                                  this is a sign that <code>REGEX</code> is not a valid regular expression.
  55.      */
  56.     public VMSFTPEntryParser() {
  57.         this(null);
  58.     }

  59.     /**
  60.      * This constructor allows the creation of a VMSFTPEntryParser object with something other than the default configuration.
  61.      *
  62.      * @param config The {@link FTPClientConfig configuration} object used to configure this parser.
  63.      * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen under normal conditions. If the exception is seen,
  64.      *                                  this is a sign that <code>REGEX</code> is not a valid regular expression.
  65.      * @since 1.4
  66.      */
  67.     public VMSFTPEntryParser(final FTPClientConfig config) {
  68.         super(REGEX);
  69.         configure(config);
  70.     }

  71.     /**
  72.      * Defines a default configuration to be used when this class is instantiated without a {@link FTPClientConfig FTPClientConfig} parameter being specified.
  73.      *
  74.      * @return the default configuration for this parser.
  75.      */
  76.     @Override
  77.     protected FTPClientConfig getDefaultConfiguration() {
  78.         return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null);
  79.     }

  80.     protected boolean isVersioning() {
  81.         return false;
  82.     }

  83.     /**
  84.      * DO NOT USE
  85.      *
  86.      * @param listStream the stream
  87.      * @return the array of files
  88.      * @throws IOException on error
  89.      * @deprecated (2.2) No other FTPFileEntryParser implementations have this method.
  90.      */
  91.     @Deprecated
  92.     public FTPFile[] parseFileList(final java.io.InputStream listStream) throws IOException {
  93.         final org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this);
  94.         engine.readServerList(listStream, null);
  95.         return engine.getFiles();
  96.     }

  97.     /**
  98.      * Parses a line of a VMS FTP server file listing and converts it into a usable format in the form of an <code>FTPFile</code> instance. If the file
  99.      * listing line doesn't describe a file, <code>null</code> is returned, otherwise a <code>FTPFile</code> instance representing the files in the
  100.      * directory is returned.
  101.      *
  102.      * @param entry A line of text from the file listing
  103.      * @return An FTPFile instance corresponding to the supplied entry
  104.      */
  105.     @Override
  106.     public FTPFile parseFTPEntry(final String entry) {
  107.         // one block in VMS equals 512 bytes
  108.         final long longBlock = 512;

  109.         if (matches(entry)) {
  110.             final FTPFile f = new FTPFile();
  111.             f.setRawListing(entry);
  112.             String name = group(1);
  113.             final String size = group(2);
  114.             final String datestr = group(3) + " " + group(4);
  115.             final String owner = group(5);
  116.             final String[] permissions = new String[3];
  117.             permissions[0] = group(9);
  118.             permissions[1] = group(10);
  119.             permissions[2] = group(11);
  120.             try {
  121.                 f.setTimestamp(super.parseTimestamp(datestr));
  122.             } catch (final ParseException e) {
  123.                 // intentionally do nothing
  124.             }

  125.             final String grp;
  126.             final String user;
  127.             final StringTokenizer t = new StringTokenizer(owner, ",");
  128.             switch (t.countTokens()) {
  129.             case 1:
  130.                 grp = null;
  131.                 user = t.nextToken();
  132.                 break;
  133.             case 2:
  134.                 grp = t.nextToken();
  135.                 user = t.nextToken();
  136.                 break;
  137.             default:
  138.                 grp = null;
  139.                 user = null;
  140.             }

  141.             if (name.lastIndexOf(".DIR") != -1) {
  142.                 f.setType(FTPFile.DIRECTORY_TYPE);
  143.             } else {
  144.                 f.setType(FTPFile.FILE_TYPE);
  145.             }
  146.             // set FTPFile name
  147.             // Check also for versions to be returned or not
  148.             if (!isVersioning()) {
  149.                 name = name.substring(0, name.lastIndexOf(';'));
  150.             }
  151.             f.setName(name);
  152.             // size is retreived in blocks and needs to be put in bytes
  153.             // for us humans and added to the FTPFile array
  154.             final long sizeInBytes = Long.parseLong(size) * longBlock;
  155.             f.setSize(sizeInBytes);

  156.             f.setGroup(grp);
  157.             f.setUser(user);
  158.             // set group and owner

  159.             // Set file permission.
  160.             // VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
  161.             // R (read) W (write) E (execute) D (delete)

  162.             // iterate for OWNER GROUP WORLD permissions
  163.             for (int access = 0; access < 3; access++) {
  164.                 final String permission = permissions[access];

  165.                 f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0);
  166.                 f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0);
  167.                 f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0);
  168.             }

  169.             return f;
  170.         }
  171.         return null;
  172.     }

  173.     // DEPRECATED METHODS - for API compatibility only - DO NOT USE

  174.     /**
  175.      * Reads the next entry using the supplied BufferedReader object up to whatever delimits one entry from the next. This parser cannot use the default
  176.      * implementation of simply calling BufferedReader.readLine(), because one entry may span multiple lines.
  177.      *
  178.      * @param reader The BufferedReader object from which entries are to be read.
  179.      *
  180.      * @return A string representing the next ftp entry or null if none found.
  181.      * @throws IOException thrown on any IO Error reading from the reader.
  182.      */
  183.     @Override
  184.     public String readNextEntry(final BufferedReader reader) throws IOException {
  185.         String line = reader.readLine();
  186.         final StringBuilder entry = new StringBuilder();
  187.         while (line != null) {
  188.             if (line.startsWith("Directory") || line.startsWith("Total")) {
  189.                 line = reader.readLine();
  190.                 continue;
  191.             }

  192.             entry.append(line);
  193.             if (line.trim().endsWith(")")) {
  194.                 break;
  195.             }
  196.             line = reader.readLine();
  197.         }
  198.         return entry.length() == 0 ? null : entry.toString();
  199.     }

  200. }