001package org.apache.maven.scm.provider.cvslib.command.login;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.scm.ScmException;
023import org.apache.maven.scm.log.ScmLogger;
024
025import java.io.BufferedReader;
026import java.io.File;
027import java.io.FileReader;
028import java.io.FileWriter;
029import java.io.IOException;
030import java.io.PrintWriter;
031
032/**
033 * Adds an new entry to a CVS password file.
034 *
035 *
036 * @todo Update this class for support password storage in cvsnt. CVSNT use the windows registry, so, we need a jni
037 * tool for access to the windows registry
038 */
039public class CvsPass
040{
041    /**
042     * CVS Root
043     */
044    private String cvsRoot = null;
045
046    /**
047     * Password file to add password to
048     */
049    private File passFile = null;
050
051    /**
052     * Password to add to file
053     */
054    private String password = null;
055
056    private ScmLogger logger;
057
058    /**
059     * Array contain char conversion data
060     */
061    private final char[] shifts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
062        24, 25, 26, 27, 28, 29, 30, 31, 114, 120, 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 111, 52,
063        75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, 41, 57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50,
064        42, 123, 91, 35, 125, 55, 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, 36, 121, 117, 104, 101,
065        100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 58, 113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223,
066        225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, 199, 170, 181, 204, 138, 232,
067        218, 183, 255, 234, 220, 247, 213, 203, 226, 193, 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238,
068        161, 179, 160, 212, 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, 192, 159,
069        244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, 227, 231, 219, 169, 175, 156, 206, 198,
070        129, 164, 150, 210, 154, 177, 134, 127, 182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236,
071        171, 195, 243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152};
072
073    /**
074     * Create a CVS task using the default cvspass file location.
075     */
076    public CvsPass( ScmLogger logger )
077    {
078        passFile = new File( System.getProperty( "cygwin.user.home", System.getProperty( "user.home" ) ) + File
079            .separatorChar + ".cvspass" );
080        this.logger = logger;
081    }
082
083    /**
084     * Does the work.
085     *
086     * @throws ScmException if something is missing
087     * @throws IOException  if something goes wrong
088     */
089    public final void execute()
090        throws ScmException, IOException
091    {
092        if ( cvsRoot == null )
093        {
094            throw new ScmException( "cvsroot is required" );
095        }
096
097        if ( logger.isDebugEnabled() )
098        {
099            logger.debug( "cvsRoot: " + cvsRoot );
100            logger.debug( "passFile: " + passFile );
101        }
102
103        BufferedReader reader = null;
104
105        PrintWriter writer = null;
106        try
107        {
108            StringBuilder buf = new StringBuilder();
109
110            if ( passFile.exists() )
111            {
112                reader = new BufferedReader( new FileReader( passFile ) );
113
114                String line = null;
115
116                while ( ( line = reader.readLine() ) != null )
117                {
118                    if ( !line.startsWith( cvsRoot ) && !line.startsWith( "/1 " + cvsRoot ) )
119                    {
120                        buf.append( line ).append( "\n" );
121                    }
122                    else
123                    {
124                        if ( logger.isDebugEnabled() )
125                        {
126                            logger.debug( "cvsroot " + cvsRoot + " already exist in " + passFile.getAbsolutePath()
127                                + ". SKIPPED." );
128                        }
129
130                        return;
131                    }
132                }
133            }
134            else
135            {
136                passFile.getParentFile().mkdirs();
137            }
138
139            if ( password == null )
140            {
141                throw new ScmException( "password is required. You must run a 'cvs -d " + cvsRoot
142                    + " login' first or provide it in the connection url." );
143            }
144
145            //logger.debug( "password: " + password );
146
147            String pwdfile = buf.toString() + "/1 " + cvsRoot + " A" + mangle( password );
148
149            if ( logger.isDebugEnabled() )
150            {
151                logger.debug( "Writing -> " + pwdfile + " in " + passFile.getAbsolutePath() );
152            }
153
154            writer = new PrintWriter( new FileWriter( passFile ) );
155
156            writer.println( pwdfile );
157        }
158        finally
159        {
160            if ( reader != null )
161            {
162                try
163                {
164                    reader.close();
165                }
166                catch ( IOException e )
167                {
168                    // ignore
169                }
170            }
171            if ( writer != null )
172            {
173                writer.close();
174            }
175        }
176    }
177
178    private String mangle( String password )
179    {
180        StringBuilder buf = new StringBuilder();
181        for ( int i = 0; i < password.length(); i++ )
182        {
183            buf.append( shifts[password.charAt( i )] );
184        }
185        return buf.toString();
186    }
187
188    /**
189     * The CVS repository to add an entry for.
190     *
191     * @param cvsRoot the CVS repository
192     */
193    public void setCvsroot( String cvsRoot )
194    {
195        this.cvsRoot = cvsRoot;
196    }
197
198    /**
199     * Password file to add the entry to.
200     *
201     * @param passFile the password file.
202     */
203    public void setPassfile( File passFile )
204    {
205        this.passFile = passFile;
206    }
207
208    /**
209     * Password to be added to the password file.
210     *
211     * @param password the password.
212     */
213    public void setPassword( String password )
214    {
215        this.password = password;
216    }
217
218}