001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.ftp.parser; 019import java.io.BufferedReader; 020import java.io.IOException; 021import java.text.ParseException; 022import java.util.StringTokenizer; 023 024import org.apache.commons.net.ftp.FTPClientConfig; 025import org.apache.commons.net.ftp.FTPFile; 026 027/** 028 * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. 029 * This is a sample of VMS LIST output 030 * <pre> 031 * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", 032 * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", 033 * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", 034 * </pre> 035 * <p> 036 * Note: VMSFTPEntryParser can only be instantiated through the 037 * DefaultFTPParserFactory by classname. It will not be chosen 038 * by the autodetection scheme. 039 * </p> 040 * 041 * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) 042 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 043 */ 044public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl 045{ 046 047 private static final String DEFAULT_DATE_FORMAT 048 = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 049 050 /** 051 * this is the regular expression used by this parser. 052 */ 053 private static final String REGEX = 054 "(.*?;[0-9]+)\\s*" //1 file and version 055 + "(\\d+)(?:/\\d+)?\\s*" //2 size/allocated 056 +"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time 057 + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner 058 + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; //9,10,11 Permissions (O,G,W) 059 // TODO - perhaps restrict permissions to [RWED]* ? 060 061 062 063 /** 064 * Constructor for a VMSFTPEntryParser object. 065 * 066 * @throws IllegalArgumentException 067 * Thrown if the regular expression is unparseable. Should not be seen 068 * under normal conditions. It it is seen, this is a sign that 069 * <code>REGEX</code> is not a valid regular expression. 070 */ 071 public VMSFTPEntryParser() 072 { 073 this(null); 074 } 075 076 /** 077 * This constructor allows the creation of a VMSFTPEntryParser object with 078 * something other than the default configuration. 079 * 080 * @param config The {@link FTPClientConfig configuration} object used to 081 * configure this parser. 082 * @throws IllegalArgumentException 083 * Thrown if the regular expression is unparseable. Should not be seen 084 * under normal conditions. It it is seen, this is a sign that 085 * <code>REGEX</code> is not a valid regular expression. 086 * @since 1.4 087 */ 088 public VMSFTPEntryParser(final FTPClientConfig config) 089 { 090 super(REGEX); 091 configure(config); 092 } 093 094 /** 095 * Parses a line of a VMS FTP server file listing and converts it into a 096 * usable format in the form of an <code> FTPFile </code> instance. If the 097 * file listing line doesn't describe a file, <code> null </code> is 098 * returned, otherwise a <code> FTPFile </code> instance representing the 099 * files in the directory is returned. 100 * 101 * @param entry A line of text from the file listing 102 * @return An FTPFile instance corresponding to the supplied entry 103 */ 104 @Override 105 public FTPFile parseFTPEntry(final String entry) 106 { 107 //one block in VMS equals 512 bytes 108 final long longBlock = 512; 109 110 if (matches(entry)) 111 { 112 final FTPFile f = new FTPFile(); 113 f.setRawListing(entry); 114 String name = group(1); 115 final String size = group(2); 116 final String datestr = group(3)+" "+group(4); 117 final String owner = group(5); 118 final String permissions[] = new String[3]; 119 permissions[0]= group(9); 120 permissions[1]= group(10); 121 permissions[2]= group(11); 122 try 123 { 124 f.setTimestamp(super.parseTimestamp(datestr)); 125 } 126 catch (final ParseException e) 127 { 128 // intentionally do nothing 129 } 130 131 132 final String grp; 133 final String user; 134 final StringTokenizer t = new StringTokenizer(owner, ","); 135 switch (t.countTokens()) { 136 case 1: 137 grp = null; 138 user = t.nextToken(); 139 break; 140 case 2: 141 grp = t.nextToken(); 142 user = t.nextToken(); 143 break; 144 default: 145 grp = null; 146 user = null; 147 } 148 149 if (name.lastIndexOf(".DIR") != -1) 150 { 151 f.setType(FTPFile.DIRECTORY_TYPE); 152 } 153 else 154 { 155 f.setType(FTPFile.FILE_TYPE); 156 } 157 //set FTPFile name 158 //Check also for versions to be returned or not 159 if (isVersioning()) 160 { 161 f.setName(name); 162 } 163 else 164 { 165 name = name.substring(0, name.lastIndexOf(';')); 166 f.setName(name); 167 } 168 //size is retreived in blocks and needs to be put in bytes 169 //for us humans and added to the FTPFile array 170 final long sizeInBytes = Long.parseLong(size) * longBlock; 171 f.setSize(sizeInBytes); 172 173 f.setGroup(grp); 174 f.setUser(user); 175 //set group and owner 176 177 //Set file permission. 178 //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain 179 //R (read) W (write) E (execute) D (delete) 180 181 //iterate for OWNER GROUP WORLD permissions 182 for (int access = 0; access < 3; access++) 183 { 184 final String permission = permissions[access]; 185 186 f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); 187 f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); 188 f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); 189 } 190 191 return f; 192 } 193 return null; 194 } 195 196 197 /** 198 * Reads the next entry using the supplied BufferedReader object up to 199 * whatever delemits one entry from the next. This parser cannot use 200 * the default implementation of simply calling BufferedReader.readLine(), 201 * because one entry may span multiple lines. 202 * 203 * @param reader The BufferedReader object from which entries are to be 204 * read. 205 * 206 * @return A string representing the next ftp entry or null if none found. 207 * @throws IOException thrown on any IO Error reading from the reader. 208 */ 209 @Override 210 public String readNextEntry(final BufferedReader reader) throws IOException 211 { 212 String line = reader.readLine(); 213 final StringBuilder entry = new StringBuilder(); 214 while (line != null) 215 { 216 if (line.startsWith("Directory") || line.startsWith("Total")) { 217 line = reader.readLine(); 218 continue; 219 } 220 221 entry.append(line); 222 if (line.trim().endsWith(")")) 223 { 224 break; 225 } 226 line = reader.readLine(); 227 } 228 return entry.length() == 0 ? null : entry.toString(); 229 } 230 231 protected boolean isVersioning() { 232 return false; 233 } 234 235 /** 236 * Defines a default configuration to be used when this class is 237 * instantiated without a {@link FTPClientConfig FTPClientConfig} 238 * parameter being specified. 239 * @return the default configuration for this parser. 240 */ 241 @Override 242 protected FTPClientConfig getDefaultConfiguration() { 243 return new FTPClientConfig( 244 FTPClientConfig.SYST_VMS, 245 DEFAULT_DATE_FORMAT, 246 null); 247 } 248 249 // DEPRECATED METHODS - for API compatibility only - DO NOT USE 250 251 /** 252 * DO NOT USE 253 * @param listStream the stream 254 * @return the array of files 255 * @throws IOException on error 256 * @deprecated (2.2) No other FTPFileEntryParser implementations have this method. 257 */ 258 @Deprecated 259 public FTPFile[] parseFileList(final java.io.InputStream listStream) throws IOException { 260 final org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this); 261 engine.readServerList(listStream, null); 262 return engine.getFiles(); 263 } 264 265}