1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.net.ftp.parser;
  17. import java.io.BufferedReader;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.util.Calendar;
  21. import java.util.StringTokenizer;
  22. import org.apache.commons.net.ftp.FTPFile;
  23. import org.apache.commons.net.ftp.FTPListParseEngine;
  24. /**
  25. * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems.
  26. * This is a sample of VMS LIST output
  27. *
  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. * <P><B>
  32. * Note: VMSFTPEntryParser can only be instantiated through the
  33. * DefaultFTPParserFactory by classname. It will not be chosen
  34. * by the autodetection scheme.
  35. * </B>
  36. * <P>
  37. *
  38. * @author <a href="Winston.Ojeda@qg.com">Winston Ojeda</a>
  39. * @author <a href="mailto:scohen@apache.org">Steve Cohen</a>
  40. * @author <a href="sestegra@free.fr">Stephane ESTE-GRACIAS</a>
  41. * @version $Id: VMSFTPEntryParser.java,v 1.23 2004/04/22 00:48:07 scohen Exp $
  42. *
  43. * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
  44. * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
  45. */
  46. public class VMSFTPEntryParser extends RegexFTPFileEntryParserImpl
  47. {
  48. /**
  49. * months abbreviations looked for by this parser. Also used
  50. * to determine <b>which</b> month has been matched by the parser.
  51. */
  52. private static final String MONTHS =
  53. "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)";
  54. /**
  55. * this is the regular expression used by this parser.
  56. */
  57. private static final String REGEX =
  58. "(.*;[0-9]+)\\s*"
  59. + "(\\d+)/\\d+\\s*"
  60. + "(\\d{1,2})-"
  61. + MONTHS
  62. + "-([0-9]{4})\\s*"
  63. + "((?:[01]\\d)|(?:2[0-3])):([012345]\\d):([012345]\\d)\\s*"
  64. + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*"
  65. + "\\([a-zA-Z]*,[a-zA-Z]*,[a-zA-Z]*,[a-zA-Z]*\\)";
  66. /**
  67. * Constructor for a VMSFTPEntryParser object.
  68. *
  69. * @exception IllegalArgumentException
  70. * Thrown if the regular expression is unparseable. Should not be seen
  71. * under normal conditions. It it is seen, this is a sign that
  72. * <code>REGEX</code> is not a valid regular expression.
  73. */
  74. public VMSFTPEntryParser()
  75. {
  76. super(REGEX);
  77. }
  78. /***
  79. * Parses an FTP server file listing and converts it into a usable format
  80. * in the form of an array of <code> FTPFile </code> instances. If the
  81. * file list contains no files, <code> null </code> should be
  82. * returned, otherwise an array of <code> FTPFile </code> instances
  83. * representing the files in the directory is returned.
  84. * <p>
  85. * @param listStream The InputStream from which the file list should be
  86. * read.
  87. * @return The list of file information contained in the given path. null
  88. * if the list could not be obtained or if there are no files in
  89. * the directory.
  90. * @exception IOException If an I/O error occurs reading the listStream.
  91. ***/
  92. public FTPFile[] parseFileList(InputStream listStream) throws IOException {
  93. FTPListParseEngine engine = new FTPListParseEngine(this);
  94. engine.readServerList(listStream);
  95. return engine.getFiles();
  96. }
  97. /**
  98. * Parses a line of a VMS FTP server file listing and converts it into a
  99. * usable format in the form of an <code> FTPFile </code> instance. If the
  100. * file listing line doesn't describe a file, <code> null </code> is
  101. * returned, otherwise a <code> FTPFile </code> instance representing the
  102. * files in the directory is returned.
  103. * <p>
  104. * @param entry A line of text from the file listing
  105. * @return An FTPFile instance corresponding to the supplied entry
  106. */
  107. public FTPFile parseFTPEntry(String entry)
  108. {
  109. //one block in VMS equals 512 bytes
  110. long longBlock = 512;
  111. if (matches(entry))
  112. {
  113. FTPFile f = new FTPFile();
  114. f.setRawListing(entry);
  115. String name = group(1);
  116. String size = group(2);
  117. String day = group(3);
  118. String mo = group(4);
  119. String yr = group(5);
  120. String hr = group(6);
  121. String min = group(7);
  122. String sec = group(8);
  123. String owner = group(9);
  124. String grp;
  125. String user;
  126. StringTokenizer t = new StringTokenizer(owner, ",");
  127. switch (t.countTokens()) {
  128. case 1:
  129. grp = null;
  130. user = t.nextToken();
  131. break;
  132. case 2:
  133. grp = t.nextToken();
  134. user = t.nextToken();
  135. break;
  136. default:
  137. grp = null;
  138. user = null;
  139. }
  140. if (name.lastIndexOf(".DIR") != -1)
  141. {
  142. f.setType(FTPFile.DIRECTORY_TYPE);
  143. }
  144. else
  145. {
  146. f.setType(FTPFile.FILE_TYPE);
  147. }
  148. //set FTPFile name
  149. //Check also for versions to be returned or not
  150. if (isVersioning())
  151. {
  152. f.setName(name);
  153. }
  154. else
  155. {
  156. name = name.substring(0, name.lastIndexOf(";"));
  157. f.setName(name);
  158. }
  159. //size is retreived in blocks and needs to be put in bytes
  160. //for us humans and added to the FTPFile array
  161. Long theSize = new Long(size);
  162. long sizeInBytes = theSize.longValue() * longBlock;
  163. f.setSize(sizeInBytes);
  164. //set the date
  165. Calendar cal = Calendar.getInstance();
  166. cal.clear();
  167. cal.set(Calendar.DATE, new Integer(day).intValue());
  168. cal.set(Calendar.MONTH, MONTHS.indexOf(mo) / 4);
  169. cal.set(Calendar.YEAR, new Integer(yr).intValue());
  170. cal.set(Calendar.HOUR_OF_DAY, new Integer(hr).intValue());
  171. cal.set(Calendar.MINUTE, new Integer(min).intValue());
  172. cal.set(Calendar.SECOND, new Integer(sec).intValue());
  173. f.setTimestamp(cal);
  174. f.setGroup(grp);
  175. f.setUser(user);
  176. //set group and owner
  177. //Since I don't need the persmissions on this file (RWED), I'll
  178. //leave that for further development. 'Cause it will be a bit
  179. //elaborate to do it right with VMSes World, Global and so forth.
  180. return f;
  181. }
  182. return null;
  183. }
  184. /**
  185. * Reads the next entry using the supplied BufferedReader object up to
  186. * whatever delemits one entry from the next. This parser cannot use
  187. * the default implementation of simply calling BufferedReader.readLine(),
  188. * because one entry may span multiple lines.
  189. *
  190. * @param reader The BufferedReader object from which entries are to be
  191. * read.
  192. *
  193. * @return A string representing the next ftp entry or null if none found.
  194. * @exception IOException thrown on any IO Error reading from the reader.
  195. */
  196. public String readNextEntry(BufferedReader reader) throws IOException
  197. {
  198. String line = reader.readLine();
  199. StringBuffer entry = new StringBuffer();
  200. while (line != null)
  201. {
  202. if (line.startsWith("Directory") || line.startsWith("Total")) {
  203. line = reader.readLine();
  204. continue;
  205. }
  206. entry.append(line);
  207. if (line.trim().endsWith(")"))
  208. {
  209. break;
  210. }
  211. line = reader.readLine();
  212. }
  213. return (entry.length() == 0 ? null : entry.toString());
  214. }
  215. protected boolean isVersioning() {
  216. return false;
  217. }
  218. }
  219. /* Emacs configuration
  220. * Local variables: **
  221. * mode: java **
  222. * c-basic-offset: 4 **
  223. * indent-tabs-mode: nil **
  224. * End: **
  225. */