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