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    
018    package org.apache.commons.net.ftp.parser;
019    import java.io.BufferedReader;
020    import java.io.IOException;
021    import java.text.ParseException;
022    import java.util.StringTokenizer;
023    
024    import org.apache.commons.net.ftp.FTPClientConfig;
025    import 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     *
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     * <P><B>
035     * Note: VMSFTPEntryParser can only be instantiated through the
036     * DefaultFTPParserFactory by classname.  It will not be chosen
037     * by the autodetection scheme.
038     * </B>
039     * <P>
040     *
041     * @author  <a href="Winston.Ojeda@qg.com">Winston Ojeda</a>
042     * @author <a href="mailto:scohen@apache.org">Steve Cohen</a>
043     * @author <a href="sestegra@free.fr">Stephane ESTE-GRACIAS</a>
044     * @version $Id: VMSFTPEntryParser.java 1299238 2012-03-10 17:12:28Z sebb $
045     *
046     * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
047     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
048     */
049    public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
050    {
051    
052        private static final String DEFAULT_DATE_FORMAT
053            = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
054    
055        /**
056         * this is the regular expression used by this parser.
057         */
058        private static final String REGEX =
059            "(.*;[0-9]+)\\s*"                                                   //1  file and version
060            + "(\\d+)/\\d+\\s*"                                                 //2  size/allocated
061            +"(\\S+)\\s+(\\S+)\\s+"                                             //3+4 date and time
062            + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner
063            + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)";            //9,10,11 Permissions (O,G,W)
064        // TODO - perhaps restrict permissions to [RWED]* ?
065    
066    
067    
068        /**
069         * Constructor for a VMSFTPEntryParser object.
070         *
071         * @exception IllegalArgumentException
072         * Thrown if the regular expression is unparseable.  Should not be seen
073         * under normal conditions.  It it is seen, this is a sign that
074         * <code>REGEX</code> is  not a valid regular expression.
075         */
076        public VMSFTPEntryParser()
077        {
078            this(null);
079        }
080    
081        /**
082         * This constructor allows the creation of a VMSFTPEntryParser object with
083         * something other than the default configuration.
084         *
085         * @param config The {@link FTPClientConfig configuration} object used to
086         * configure this parser.
087         * @exception IllegalArgumentException
088         * Thrown if the regular expression is unparseable.  Should not be seen
089         * under normal conditions.  It it is seen, this is a sign that
090         * <code>REGEX</code> is  not a valid regular expression.
091         * @since 1.4
092         */
093        public VMSFTPEntryParser(FTPClientConfig config)
094        {
095            super(REGEX);
096            configure(config);
097        }
098    
099        /**
100         * Parses a line of a VMS FTP server file listing and converts it into a
101         * usable format in the form of an <code> FTPFile </code> instance.  If the
102         * file listing line doesn't describe a file, <code> null </code> is
103         * returned, otherwise a <code> FTPFile </code> instance representing the
104         * files in the directory is returned.
105         * <p>
106         * @param entry A line of text from the file listing
107         * @return An FTPFile instance corresponding to the supplied entry
108         */
109        public FTPFile parseFTPEntry(String entry)
110        {
111            //one block in VMS equals 512 bytes
112            long longBlock = 512;
113    
114            if (matches(entry))
115            {
116                FTPFile f = new FTPFile();
117                f.setRawListing(entry);
118                String name = group(1);
119                String size = group(2);
120                String datestr = group(3)+" "+group(4);
121                String owner = group(5);
122                String permissions[] = new String[3];
123                permissions[0]= group(9);
124                permissions[1]= group(10);
125                permissions[2]= group(11);
126                try
127                {
128                    f.setTimestamp(super.parseTimestamp(datestr));
129                }
130                catch (ParseException e)
131                {
132                     // intentionally do nothing
133                }
134    
135    
136                String grp;
137                String user;
138                StringTokenizer t = new StringTokenizer(owner, ",");
139                switch (t.countTokens()) {
140                    case 1:
141                        grp  = null;
142                        user = t.nextToken();
143                        break;
144                    case 2:
145                        grp  = t.nextToken();
146                        user = t.nextToken();
147                        break;
148                    default:
149                        grp  = null;
150                        user = null;
151                }
152    
153                if (name.lastIndexOf(".DIR") != -1)
154                {
155                    f.setType(FTPFile.DIRECTORY_TYPE);
156                }
157                else
158                {
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                {
165                    f.setName(name);
166                }
167                else
168                {
169                    name = name.substring(0, name.lastIndexOf(";"));
170                    f.setName(name);
171                }
172                //size is retreived in blocks and needs to be put in bytes
173                //for us humans and added to the FTPFile array
174                long sizeInBytes = Long.parseLong(size) * longBlock;
175                f.setSize(sizeInBytes);
176    
177                f.setGroup(grp);
178                f.setUser(user);
179                //set group and owner
180    
181                //Set file permission.
182                //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
183                //R (read) W (write) E (execute) D (delete)
184    
185                //iterate for OWNER GROUP WORLD permissions
186                for (int access = 0; access < 3; access++)
187                {
188                    String permission = permissions[access];
189    
190                    f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0);
191                    f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0);
192                    f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0);
193                }
194    
195                return f;
196            }
197            return null;
198        }
199    
200    
201        /**
202         * Reads the next entry using the supplied BufferedReader object up to
203         * whatever delemits one entry from the next.   This parser cannot use
204         * the default implementation of simply calling BufferedReader.readLine(),
205         * because one entry may span multiple lines.
206         *
207         * @param reader The BufferedReader object from which entries are to be
208         * read.
209         *
210         * @return A string representing the next ftp entry or null if none found.
211         * @exception IOException thrown on any IO Error reading from the reader.
212         */
213        @Override
214        public String readNextEntry(BufferedReader reader) throws IOException
215        {
216            String line = reader.readLine();
217            StringBuilder entry = new StringBuilder();
218            while (line != null)
219            {
220                if (line.startsWith("Directory") || line.startsWith("Total")) {
221                    line = reader.readLine();
222                    continue;
223                }
224    
225                entry.append(line);
226                if (line.trim().endsWith(")"))
227                {
228                    break;
229                }
230                line = reader.readLine();
231            }
232            return (entry.length() == 0 ? null : entry.toString());
233        }
234    
235        protected boolean isVersioning() {
236            return false;
237        }
238    
239        /**
240         * Defines a default configuration to be used when this class is
241         * instantiated without a {@link  FTPClientConfig  FTPClientConfig}
242         * parameter being specified.
243         * @return the default configuration for this parser.
244         */
245        @Override
246        protected FTPClientConfig getDefaultConfiguration() {
247            return new FTPClientConfig(
248                    FTPClientConfig.SYST_VMS,
249                    DEFAULT_DATE_FORMAT,
250                    null, null, null, null);
251        }
252    
253        // DEPRECATED METHODS - for API compatibility only - DO NOT USE
254    
255        /**
256         * DO NOT USE
257         * @deprecated (2.2) No other FTPFileEntryParser implementations have this method.
258         */
259        @Deprecated
260        public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException {
261            org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this);
262            engine.readServerList(listStream, null);
263            return engine.getFiles();
264        }
265    
266    }
267    
268    /* Emacs configuration
269     * Local variables:        **
270     * mode:             java  **
271     * c-basic-offset:   4     **
272     * indent-tabs-mode: nil   **
273     * End:                    **
274     */