View Javadoc
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  
18  package org.apache.commons.net.ftp.parser;
19  
20  import java.io.BufferedReader;
21  import java.io.IOException;
22  import java.text.ParseException;
23  import java.util.StringTokenizer;
24  
25  import org.apache.commons.net.ftp.FTPClientConfig;
26  import org.apache.commons.net.ftp.FTPFile;
27  
28  /**
29   * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. This is a sample of VMS LIST output
30   *
31   * <pre>
32   *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
33   *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
34   *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
35   * </pre>
36   * <p>
37   * Note: VMSFTPEntryParser can only be instantiated through the DefaultFTPParserFactory by classname. It will not be chosen by the autodetection scheme.
38   * </p>
39   *
40   * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
41   * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
42   */
43  public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
44  
45      private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; // 9-NOV-2001 12:30:24
46  
47      /**
48       * this is the regular expression used by this parser.
49       */
50      private static final String REGEX = "(.*?;[0-9]+)\\s*" // 1 file and version
51              + "(\\d+)(?:/\\d+)?\\s*" // 2 size/allocated
52              + "(\\S+)\\s+(\\S+)\\s+" // 3+4 date and time
53              + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" // 5(6,7,8) owner
54              + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; // 9,10,11 Permissions (O,G,W)
55      // TODO - perhaps restrict permissions to [RWED]* ?
56  
57      /**
58       * Constructor for a VMSFTPEntryParser object.
59       *
60       * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen under normal conditions. If the exception is seen,
61       *                                  this is a sign that <code>REGEX</code> is not a valid regular expression.
62       */
63      public VMSFTPEntryParser() {
64          this(null);
65      }
66  
67      /**
68       * This constructor allows the creation of a VMSFTPEntryParser object with something other than the default configuration.
69       *
70       * @param config The {@link FTPClientConfig configuration} object used to configure this parser.
71       * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen under normal conditions. If the exception is seen,
72       *                                  this is a sign that <code>REGEX</code> is not a valid regular expression.
73       * @since 1.4
74       */
75      public VMSFTPEntryParser(final FTPClientConfig config) {
76          super(REGEX);
77          configure(config);
78      }
79  
80      /**
81       * Defines a default configuration to be used when this class is instantiated without a {@link FTPClientConfig FTPClientConfig} parameter being specified.
82       *
83       * @return the default configuration for this parser.
84       */
85      @Override
86      protected FTPClientConfig getDefaultConfiguration() {
87          return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null);
88      }
89  
90      protected boolean isVersioning() {
91          return false;
92      }
93  
94      /**
95       * DO NOT USE
96       *
97       * @param listStream the stream
98       * @return the array of files
99       * @throws IOException on error
100      * @deprecated (2.2) No other FTPFileEntryParser implementations have this method.
101      */
102     @Deprecated
103     public FTPFile[] parseFileList(final java.io.InputStream listStream) throws IOException {
104         final org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this);
105         engine.readServerList(listStream, null);
106         return engine.getFiles();
107     }
108 
109     /**
110      * 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
111      * listing line doesn't describe a file, <code> null </code> is returned, otherwise a <code> FTPFile </code> instance representing the files in the
112      * directory is returned.
113      *
114      * @param entry A line of text from the file listing
115      * @return An FTPFile instance corresponding to the supplied entry
116      */
117     @Override
118     public FTPFile parseFTPEntry(final String entry) {
119         // one block in VMS equals 512 bytes
120         final long longBlock = 512;
121 
122         if (matches(entry)) {
123             final FTPFile f = new FTPFile();
124             f.setRawListing(entry);
125             String name = group(1);
126             final String size = group(2);
127             final String datestr = group(3) + " " + group(4);
128             final String owner = group(5);
129             final String[] permissions = new String[3];
130             permissions[0] = group(9);
131             permissions[1] = group(10);
132             permissions[2] = group(11);
133             try {
134                 f.setTimestamp(super.parseTimestamp(datestr));
135             } catch (final ParseException e) {
136                 // intentionally do nothing
137             }
138 
139             final String grp;
140             final String user;
141             final StringTokenizer t = new StringTokenizer(owner, ",");
142             switch (t.countTokens()) {
143             case 1:
144                 grp = null;
145                 user = t.nextToken();
146                 break;
147             case 2:
148                 grp = t.nextToken();
149                 user = t.nextToken();
150                 break;
151             default:
152                 grp = null;
153                 user = null;
154             }
155 
156             if (name.lastIndexOf(".DIR") != -1) {
157                 f.setType(FTPFile.DIRECTORY_TYPE);
158             } else {
159                 f.setType(FTPFile.FILE_TYPE);
160             }
161             // set FTPFile name
162             // Check also for versions to be returned or not
163             if (!isVersioning()) {
164                 name = name.substring(0, name.lastIndexOf(';'));
165             }
166             f.setName(name);
167             // size is retreived in blocks and needs to be put in bytes
168             // for us humans and added to the FTPFile array
169             final long sizeInBytes = Long.parseLong(size) * longBlock;
170             f.setSize(sizeInBytes);
171 
172             f.setGroup(grp);
173             f.setUser(user);
174             // set group and owner
175 
176             // Set file permission.
177             // VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
178             // R (read) W (write) E (execute) D (delete)
179 
180             // iterate for OWNER GROUP WORLD permissions
181             for (int access = 0; access < 3; access++) {
182                 final String permission = permissions[access];
183 
184                 f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0);
185                 f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0);
186                 f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0);
187             }
188 
189             return f;
190         }
191         return null;
192     }
193 
194     // DEPRECATED METHODS - for API compatibility only - DO NOT USE
195 
196     /**
197      * Reads the next entry using the supplied BufferedReader object up to whatever delimits one entry from the next. This parser cannot use the default
198      * implementation of simply calling BufferedReader.readLine(), because one entry may span multiple lines.
199      *
200      * @param reader The BufferedReader object from which entries are to be read.
201      *
202      * @return A string representing the next ftp entry or null if none found.
203      * @throws IOException thrown on any IO Error reading from the reader.
204      */
205     @Override
206     public String readNextEntry(final BufferedReader reader) throws IOException {
207         String line = reader.readLine();
208         final StringBuilder entry = new StringBuilder();
209         while (line != null) {
210             if (line.startsWith("Directory") || line.startsWith("Total")) {
211                 line = reader.readLine();
212                 continue;
213             }
214 
215             entry.append(line);
216             if (line.trim().endsWith(")")) {
217                 break;
218             }
219             line = reader.readLine();
220         }
221         return entry.length() == 0 ? null : entry.toString();
222     }
223 
224 }