Source Code Cross Referenced for CVSProject.java in  » Source-Control » jcvsweb » com » ice » cvsc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Source Control » jcvsweb » com.ice.cvsc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         ** Java cvs client library package.
0003:         ** Copyright (c) 1997-2002 by Timothy Gerard Endres
0004:         ** 
0005:         ** This program is free software.
0006:         ** 
0007:         ** You may redistribute it and/or modify it under the terms of the GNU
0008:         ** Library General Public License (LGPL) as published by the Free Software
0009:         ** Foundation.
0010:         **
0011:         ** Version 2 of the license should be included with this distribution in
0012:         ** the file LICENSE.txt, as well as License.html. If the license is not
0013:         ** included	with this distribution, you may find a copy at the FSF web
0014:         ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the Free
0015:         ** Software Foundation at 59 Temple Place - Suite 330, Boston, MA 02111 USA.
0016:         **
0017:         ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
0018:         ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
0019:         ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
0020:         ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
0021:         ** REDISTRIBUTION OF THIS SOFTWARE. 
0022:         ** 
0023:         */
0024:
0025:        package com.ice.cvsc;
0026:
0027:        import java.io.*;
0028:        import java.lang.*;
0029:        import java.text.*;
0030:        import java.util.*;
0031:        import java.util.zip.*;
0032:
0033:        /**
0034:         * The CVSProject class implements the concept of a local
0035:         * CVS project directory. A local project directory can be
0036:         * thought of as a local source code working directory that
0037:         * contains a CVS directory containing CVS administration files.
0038:         *
0039:         * Combined with CVSClient, this class provides everything
0040:         * you need to communicate with a CVS Server and maintain
0041:         * local working directories for CVS repositories.
0042:         *
0043:         * @version $Revision: 2.26 $
0044:         * @author Timothy Gerard Endres, <time@gjt.org>.
0045:         * @see CVSClient
0046:         *
0047:         */
0048:
0049:        //
0050:        // NOTES in code:
0051:        //
0052:        // NB-eol  Nick Bower <nick@brainstorm.co.uk>
0053:        //   Nick Bower's EOL fix. The problem was that our line reader did
0054:        //   not include the EOL line termination. This made is impossible to
0055:        //   distinguish between an end-of-file line with no termination, and
0056:        //   a line that included termination. By explicitly returning the
0057:        //   EOL (and adjusting for its existence), we eliminate this problem.
0058:        //   The problem manifested as adding line termination to files that
0059:        //   lacked it on the last line. Some complained that it affected
0060:        //   binary files checked in as ascii. That is another issue entirely!
0061:        //
0062:        // MTT-delete  Matthias Tichy <mtt@uni-paderborn.de>
0063:        //   Code to delete the local file when a "removed" command is received.
0064:        //
0065:        // MTT-null-list  Matthias Tichy <mtt@uni-paderborn.de>
0066:        //   Fixed to properly handle a null file file.
0067:        //
0068:        // GG-dot-rep  Gérard COLLIN <gcollin@netonomy.com>
0069:        //   When we see a repository string of ".", it should be ignored.
0070:        //
0071:
0072:        public class CVSProject extends Object implements  CVSResponseHandler {
0073:            static public final String RCS_ID = "$Id: CVSProject.java,v 2.26 2003/07/27 01:08:32 time Exp $";
0074:            static public final String RCS_REV = "$Revision: 2.26 $";
0075:
0076:            static private final String INFO_PREFIX = "#   ";
0077:            static private final String ERROR_PREFIX = "*** ";
0078:            static private final String NOTICE_PREFIX = "==> ";
0079:
0080:            static public boolean overTraceRequest = false;
0081:            static public boolean overTraceResponse = false;
0082:            static public boolean overTraceProcessing = false;
0083:            static public boolean overTraceTCP = false;
0084:
0085:            static public boolean deepDebug = false;
0086:            static public boolean debugEntryIO = false;
0087:
0088:            private boolean valid;
0089:            private boolean isPServer;
0090:            private boolean allowGzipFileMode;
0091:            private int gzipStreamLevel;
0092:
0093:            private int connMethod;
0094:            private int connPort;
0095:            private String serverCommand;
0096:            private String rshProcess;
0097:            private String userName;
0098:            private String password;
0099:
0100:            private String tempPath;
0101:            private String repository;
0102:            private String rootDirectory;
0103:            private String localRootDirectory;
0104:
0105:            private String[] setVars;
0106:
0107:            private File localRootDirFile;
0108:            private File localAdminDirFile;
0109:
0110:            private CVSClient client;
0111:            private CVSIgnore ignore;
0112:            private CVSProjectDef projectDef;
0113:
0114:            private CVSEntry rootEntry;
0115:            private Hashtable pathTable;
0116:
0117:            /**
0118:             * Determines if a pathname, provided by the dirName
0119:             * parameter, is a valid CVS administration directory
0120:             * (i.e., is a directory named 'CVS').
0121:             *
0122:             * @param dirName the pathname of the directory in question
0123:             */
0124:            // UNDONE separator
0125:            public static boolean isValidAdminPath(String dirName) {
0126:                if (!CVSCUtilities.caseSensitivePathNames()) {
0127:                    dirName = dirName.toUpperCase();
0128:                    CVSTracer.traceIf(CVSProject.deepDebug,
0129:                            "CVSProject.isValidAdminPath:\n"
0130:                                    + "   adjusted dirName to '" + dirName
0131:                                    + "'");
0132:                }
0133:
0134:                return (dirName.endsWith("/CVS") || dirName.endsWith("/CVS/"));
0135:            }
0136:
0137:            /**
0138:             * Given a root path, returns the administration directory
0139:             * path corresponding to root's project.
0140:             *
0141:             * @param dirName the pathname of the root directory
0142:             */
0143:            // UNDONE separator
0144:            public static String rootPathToAdminPath(String dirName) {
0145:                return dirName + (dirName.endsWith("/") ? "" : "/") + "CVS";
0146:            }
0147:
0148:            /**
0149:             * Parses a valid CVS Administration Directory path
0150:             * and returns the pathname of the working directory
0151:             * that the administration directory belongs to. In
0152:             * other words, it returns the directory's parent.
0153:             *
0154:             * @param dirName the pathname of the admin directory
0155:             */
0156:            // UNDONE separator
0157:            public static String adminPathToRootPath(String dirName) {
0158:                String path = dirName;
0159:
0160:                if (path.endsWith("/")) {
0161:                    path = path.substring(0, (path.length() - 1));
0162:                }
0163:
0164:                int index = path.lastIndexOf('/');
0165:
0166:                if (index < 0) {
0167:                    return path;
0168:                } else {
0169:                    return path.substring(0, index);
0170:                }
0171:            }
0172:
0173:            /**
0174:             * Parses a valid CVS Entries File pathname and
0175:             * returns the pathname of the admin directory
0176:             * that the entries files belongs to. In other
0177:             * words, it returns the directory's parent.
0178:             *
0179:             * @param entriesPath The pathname of the Entries file.
0180:             */
0181:            // UNDONE separator
0182:            public static String entriesPathToAdminPath(String entriesPath) {
0183:                int index = entriesPath.lastIndexOf('/');
0184:
0185:                if (index < 0) {
0186:                    // UNDONE
0187:                    return null;
0188:                }
0189:
0190:                return entriesPath.substring(0, index);
0191:            }
0192:
0193:            /**
0194:             * Verifies that a directory path is a valid CVS
0195:             * administration directory. This checks for the
0196:             * correct name ('CVS'), and that the necessary
0197:             * files ('Entries', 'Root' and 'Repository') are
0198:             * present.
0199:             *
0200:             * @param dirName the pathname of the admin directory
0201:             * @return true if directory is valid, otherwise false
0202:             */
0203:
0204:            public static boolean verifyAdminDirectory(String dirName) {
0205:                File file;
0206:
0207:                CVSTracer.traceIf(
0208:                        (CVSProject.deepDebug || CVSProject.debugEntryIO),
0209:                        "CVSProject.verifyAdminDirectory:\n" + "   dirName = '"
0210:                                + dirName + "'");
0211:
0212:                if (!CVSProject.isValidAdminPath(dirName)) {
0213:                    CVSTracer.traceIf(
0214:                            (CVSProject.deepDebug || CVSProject.debugEntryIO),
0215:                            "CVSProject.verifyAdminDirectory:\n"
0216:                                    + "   IS NOT a valid admin directory.");
0217:                    return false;
0218:                }
0219:
0220:                // NOTE
0221:                // Do NOT export until after the verify, as it uses slashes!
0222:                //
0223:                dirName = CVSCUtilities.exportPath(CVSCUtilities
0224:                        .stripFinalSlash(dirName));
0225:
0226:                file = new File(dirName, "Entries");
0227:                if (!file.exists()) {
0228:                    CVSTracer.traceIf(
0229:                            (CVSProject.deepDebug || CVSProject.debugEntryIO),
0230:                            "CVSProject.verifyAdminDirectory:\n"
0231:                                    + "   DOES NOT EXIST --> 'Entries'.");
0232:                    return false;
0233:                }
0234:
0235:                file = new File(dirName, "Repository");
0236:                if (!file.exists()) {
0237:                    CVSTracer.traceIf(
0238:                            (CVSProject.deepDebug || CVSProject.debugEntryIO),
0239:                            "CVSProject.verifyAdminDirectory:\n"
0240:                                    + "   DOES NOT EXIST --> 'Repository'.");
0241:                    return false;
0242:                }
0243:
0244:                file = new File(dirName, "Root");
0245:                if (!file.exists()) {
0246:                    CVSTracer.traceIf(
0247:                            (CVSProject.deepDebug || CVSProject.debugEntryIO),
0248:                            "CVSProject.verifyAdminDirectory:\n"
0249:                                    + "   DOES NOT EXIST --> 'Root'.");
0250:                    return false;
0251:                }
0252:
0253:                return true;
0254:            }
0255:
0256:            /**
0257:             * Given the administrative directory pathname, return
0258:             * the full pathname of the 'Entries' file.
0259:             *
0260:             * @param adminDirPath The pathname of the admin ('CVS') directory.
0261:             */
0262:            // UNDONE separator
0263:            public static String getAdminEntriesPath(String adminDirPath) {
0264:                return (adminDirPath + "/Entries");
0265:            }
0266:
0267:            /**
0268:             * Given the administrative directory pathname, return
0269:             * the full pathname of the 'Repository' file.
0270:             *
0271:             * @param adminDirPath The pathname of the admin ('CVS') directory.
0272:             */
0273:            // UNDONE separator
0274:            public static String getAdminRepositoryPath(String adminDirPath) {
0275:                return (adminDirPath + "/Repository");
0276:            }
0277:
0278:            /**
0279:             * Given the administrative directory pathname, return
0280:             * the full pathname of the 'Root' file.
0281:             *
0282:             * @param adminDirPath The pathname of the admin ('CVS') directory.
0283:             */
0284:            // UNDONE separator
0285:            public static String getAdminRootPath(String adminDirPath) {
0286:                return (adminDirPath + "/Root");
0287:            }
0288:
0289:            /**
0290:             * Given the administrative directory pathname, return
0291:             * the full pathname of the 'Notify' file.
0292:             *
0293:             * @param adminDirPath The pathname of the admin ('CVS') directory.
0294:             */
0295:            // UNDONE separator
0296:            public static String getAdminNotifyPath(String adminDirPath) {
0297:                return (adminDirPath + "/Notify");
0298:            }
0299:
0300:            /**
0301:             * Given the administrative directory pathname, return
0302:             * the full pathname of the project preferences file.
0303:             *
0304:             * @param adminDirPath The pathname of the admin ('CVS') directory.
0305:             */
0306:            // UNDONE separator
0307:            public static String getAdminPrefsPath(String adminDirPath) {
0308:                return (adminDirPath + "/jcvs.txt");
0309:            }
0310:
0311:            /**
0312:             * Constructs a new CVSProject object.
0313:             */
0314:            public CVSProject() {
0315:                super ();
0316:
0317:                this .initFields();
0318:
0319:                this .client = null;
0320:            }
0321:
0322:            /*
0323:             * Constructs a new CVSProject object with the
0324:             * provided pro.
0325:             *
0326:            public
0327:            CVSProject( String projectName )
0328:            	{
0329:            	super();
0330:
0331:            	this.initFields();
0332:
0333:            	this.projectName = projectName;
0334:            	}
0335:             *
0336:             */
0337:
0338:            /**
0339:             * Constructs a new CVSProject object, setting the
0340:             * project's client to the one provided.
0341:             *
0342:             * @param client A CVSClient object to be used by this
0343:             * project for all CVS server requests.
0344:             */
0345:            public CVSProject(CVSClient client) {
0346:                super ();
0347:
0348:                this .initFields();
0349:
0350:                this .client = client;
0351:            }
0352:
0353:            /**
0354:             * Internal nethod used by constructors to initialize
0355:             * the project's fields.
0356:             */
0357:            private void initFields() {
0358:                this .valid = false;
0359:                this .isPServer = false;
0360:                this .allowGzipFileMode = true;
0361:                this .gzipStreamLevel = 0;
0362:
0363:                this .userName = "";
0364:
0365:                // NOTE password == 'null' indicates "no login yet"
0366:                this .password = null;
0367:
0368:                this .connMethod = CVSRequest.METHOD_RSH;
0369:                this .connPort = CVSClient.DEFAULT_CVS_PORT;
0370:                this .serverCommand = "cvs server";
0371:                this .rshProcess = null;
0372:
0373:                this .repository = null;
0374:                this .rootDirectory = null;
0375:                this .localRootDirectory = null;
0376:
0377:                this .client = null;
0378:                this .projectDef = null;
0379:
0380:                this .setVars = null;
0381:
0382:                this .ignore = new CVSIgnore();
0383:
0384:                this .rootEntry = null;
0385:                this .pathTable = new Hashtable();
0386:
0387:                this .tempPath = null;
0388:
0389:                this .localRootDirFile = null;
0390:                this .localAdminDirFile = null;
0391:            }
0392:
0393:            /**
0394:             * Returns the client this project is set to use.
0395:             * 
0396:             * @return the project's client.
0397:             * @see CVSClient
0398:             */
0399:
0400:            public CVSClient getClient() {
0401:                return this .client;
0402:            }
0403:
0404:            public void setClient(CVSClient client) {
0405:                this .client = client;
0406:            }
0407:
0408:            public String getRepository() {
0409:                return this .repository;
0410:            }
0411:
0412:            public void setRepository(String repository) {
0413:                this .repository = repository;
0414:            }
0415:
0416:            public boolean isPServer() {
0417:                return this .isPServer;
0418:            }
0419:
0420:            public void setPServer(boolean isPServer) {
0421:                this .isPServer = isPServer;
0422:            }
0423:
0424:            public boolean allowsGzipFileMode() {
0425:                return this .allowGzipFileMode;
0426:            }
0427:
0428:            public void setAllowsGzipFileMode(boolean allow) {
0429:                this .allowGzipFileMode = allow;
0430:            }
0431:
0432:            public int getGzipStreamLevel() {
0433:                return this .gzipStreamLevel;
0434:            }
0435:
0436:            public void setGzipStreamLevel(int level) {
0437:                this .gzipStreamLevel = level;
0438:            }
0439:
0440:            public String getUserName() {
0441:                return this .userName;
0442:            }
0443:
0444:            public void setUserName(String name) {
0445:                this .userName = name;
0446:            }
0447:
0448:            public String getPassword() {
0449:                return this .password;
0450:            }
0451:
0452:            public void setPassword(String password) {
0453:                this .password = password;
0454:            }
0455:
0456:            public String getRootDirectory() {
0457:                return this .rootDirectory;
0458:            }
0459:
0460:            public void setRootDirectory(String rootDirectory) {
0461:                this .rootDirectory = rootDirectory;
0462:            }
0463:
0464:            /**
0465:             * Returns the <em>full</em> local pathname for the
0466:             * root directory of this project.
0467:             *
0468:             * @return Full pathname of project's local root directory.
0469:             */
0470:
0471:            public String getLocalRootPath() {
0472:                return this .localRootDirectory;
0473:                //		+ "/" + this.rootEntry.getName();
0474:            }
0475:
0476:            public String getLocalRootDirectory() {
0477:                return this .localRootDirectory;
0478:            }
0479:
0480:            public void setLocalRootDirectory(String dirName) {
0481:                this .localRootDirectory = dirName;
0482:
0483:                this .localRootDirFile = new File(dirName);
0484:
0485:                this .localAdminDirFile = // UNDONE separator
0486:                new File(dirName + "/CVS");
0487:            }
0488:
0489:            public String getTempDirectory() {
0490:                return this .tempPath;
0491:            }
0492:
0493:            public void setTempDirectory(String dirName) {
0494:                this .tempPath = dirName;
0495:                if (this .client != null) {
0496:                    this .client.setTempDirectory(dirName);
0497:                }
0498:            }
0499:
0500:            public int getConnectionPort() {
0501:                return this .connPort;
0502:            }
0503:
0504:            public void setConnectionPort(int port) {
0505:                this .connPort = port;
0506:            }
0507:
0508:            public int getConnectionMethod() {
0509:                return this .connMethod;
0510:            }
0511:
0512:            public void setConnectionMethod(int method) {
0513:                this .connMethod = method;
0514:            }
0515:
0516:            public boolean isSSHServer() {
0517:                return (this .connMethod == CVSRequest.METHOD_SSH);
0518:            }
0519:
0520:            public String getServerCommand() {
0521:                return this .serverCommand;
0522:            }
0523:
0524:            public void setServerCommand(String command) {
0525:                this .serverCommand = command;
0526:            }
0527:
0528:            public String getRshProcess() {
0529:                return this .rshProcess;
0530:            }
0531:
0532:            public void setRshProcess(String rshProcess) {
0533:                this .rshProcess = rshProcess;
0534:            }
0535:
0536:            /**
0537:             * Returns the project's user set variables.
0538:             *
0539:             * @return The project's user set variables.
0540:             */
0541:            public String[] getSetVariables() {
0542:                return this .setVars;
0543:            }
0544:
0545:            /**
0546:             * Sets the project's user set variables.
0547:             *
0548:             * @param vars The new user set variables.
0549:             */
0550:            public void setSetVariables(String[] vars) {
0551:                this .setVars = vars;
0552:            }
0553:
0554:            public CVSEntry getRootEntry() {
0555:                return this .rootEntry;
0556:            }
0557:
0558:            public CVSProjectDef getProjectDef() {
0559:                return this .projectDef;
0560:            }
0561:
0562:            public void setProjectDef(CVSProjectDef projectDef) {
0563:                this .projectDef = projectDef;
0564:            }
0565:
0566:            public File getEntryFile(CVSEntry entry) {
0567:                String relPath;
0568:
0569:                relPath = entry.getFullName();
0570:
0571:                File file = new File(CVSCUtilities
0572:                        .exportPath(this .localRootDirFile.getPath()),
0573:                        CVSCUtilities.exportPath(entry.getFullPathName()));
0574:
0575:                if (CVSProject.deepDebug)
0576:                    CVSTracer.traceIf(false,
0577:                            "CVSProject.getEntryFile: relPath '" + relPath
0578:                                    + "' localRootDir '"
0579:                                    + this .localRootDirFile.getPath()
0580:                                    + "' result '" + file.getPath() + "'");
0581:
0582:                return file;
0583:            }
0584:
0585:            public boolean hasValidLogin(String userName) {
0586:                if (this .userName.equals(userName))
0587:                    if (this .password != null)
0588:                        return true;
0589:
0590:                return false;
0591:            }
0592:
0593:            public void addEntryNotify(CVSEntryVector entries, String type,
0594:                    String options) {
0595:                PrintWriter out;
0596:                String noteLine;
0597:
0598:                // REVIEW
0599:                // UNDONE
0600:                // We are INCOMPATIBLE with the cvs command line here!!!
0601:                // The command line stores this file in each working directory's
0602:                // admin directory, NOT in the root admin like we are! This means
0603:                // that the command line will get all of our notifies, ( will it
0604:                // choke on them?), but we will not get all of the command line's.
0605:                // Why?! Performance. Does it matter?
0606:                // 
0607:                String fileName = CVSProject.getAdminNotifyPath(CVSProject
0608:                        .rootPathToAdminPath(this .getLocalRootPath()));
0609:
0610:                try {
0611:                    out = new PrintWriter(new FileWriter(fileName, true));
0612:                } catch (IOException ex) {
0613:                    CVSTracer
0614:                            .traceWithStack("ERROR opening Notification file '"
0615:                                    + fileName + "' for append");
0616:                    return;
0617:                }
0618:
0619:                CVSTimestamp now = new CVSTimestamp();
0620:                CVSTimestampFormat stamper = CVSTimestampFormat.getInstance();
0621:
0622:                String stampStr = stamper.format(now);
0623:
0624:                for (int eIdx = 0; entries != null && eIdx < entries.size(); ++eIdx) {
0625:                    CVSEntry entry = entries.entryAt(eIdx);
0626:                    if (entry != null) {
0627:                        out.println(type + entry.getName() + "\t"
0628:                                + stamper.format(now) + " GMT" + "\t"
0629:                                + "remote.via.jCVS" + "\t"
0630:                                + entry.getLocalDirectory() + "\t" + options);
0631:                    } else {
0632:                        CVSTracer.traceWithStack("NULL ENTRY[" + eIdx
0633:                                + "] on index '" + eIdx + "'");
0634:                    }
0635:                }
0636:
0637:                out.flush();
0638:                out.close();
0639:            }
0640:
0641:            public void includeNotifies(CVSRequest request) {
0642:                BufferedReader in;
0643:                String noteLine;
0644:
0645:                request.notifies = new Vector();
0646:
0647:                if (this .rootEntry == null)
0648:                    return;
0649:
0650:                File notFile = new File(CVSProject
0651:                        .getAdminNotifyPath(CVSProject.rootPathToAdminPath(this 
0652:                                .getLocalRootPath())));
0653:
0654:                if (notFile.exists()) {
0655:                    try {
0656:                        in = new BufferedReader(new FileReader(notFile));
0657:                    } catch (IOException ex) {
0658:                        CVSLog.logMsg("ERROR opening Notification file '"
0659:                                + notFile.getPath() + "'");
0660:                        return;
0661:                    }
0662:
0663:                    for (;;) {
0664:                        try {
0665:                            noteLine = in.readLine();
0666:                        } catch (IOException ex) {
0667:                            CVSLog.logMsg("ERROR reading Notification file '"
0668:                                    + notFile.getPath() + "'");
0669:                            noteLine = null;
0670:                        }
0671:
0672:                        if (noteLine == null)
0673:                            break;
0674:
0675:                        // NB-eol
0676:                        // Now need this because NewLineReader.readLine
0677:                        // returns an eol.
0678:                        noteLine = noteLine.trim();
0679:
0680:                        CVSNotifyItem notifyItem = parseNotifyLine(noteLine);
0681:
0682:                        if (notifyItem != null) {
0683:                            request.notifies.addElement(notifyItem);
0684:                        } else {
0685:                            CVSLog.logMsg("ERROR bad 'CVS/Notify' line:\n"
0686:                                    + "   " + noteLine);
0687:                        }
0688:                    }
0689:
0690:                    try {
0691:                        in.close();
0692:                    } catch (IOException ex) {
0693:                    }
0694:                }
0695:            }
0696:
0697:            public boolean verifyPassword(CVSUserInterface ui, String userName,
0698:                    String password, boolean trace) {
0699:                CVSRequest request;
0700:                boolean result = false;
0701:
0702:                if (!this .isPServer() && !this .isSSHServer())
0703:                    return true;
0704:
0705:                if (this .hasValidLogin(userName))
0706:                    return true;
0707:
0708:                String scrambled = CVSScramble.scramblePassword(password, 'A');
0709:
0710:                request = new CVSRequest();
0711:
0712:                request.setPServer(this .isPServer());
0713:                request.setUserName(userName);
0714:                request.setPassword(this .isSSHServer() ? password : scrambled);
0715:
0716:                request.setPort(this .getClient().getPort());
0717:                request.setHostName(this .getClient().getHostName());
0718:
0719:                request.setRepository(this .repository);
0720:                request.setRootDirectory(this .rootDirectory);
0721:                request.setLocalDirectory(this .localRootDirectory);
0722:
0723:                request.verificationOnly = true;
0724:
0725:                request.traceRequest = trace;
0726:                request.traceResponse = trace;
0727:                request.traceProcessing = trace;
0728:                request.traceTCPData = trace;
0729:                request.allowGzipFileMode = this .allowGzipFileMode;
0730:                request.gzipStreamLevel = this .gzipStreamLevel;
0731:
0732:                request.setConnectionMethod(this .getConnectionMethod());
0733:                request.setServerCommand(this .getServerCommand());
0734:                request.setRshProcess(this .getRshProcess());
0735:
0736:                request.setUserInterface(ui);
0737:
0738:                CVSResponse response = client.processCVSRequest(request);
0739:
0740:                if (response.getStatus() == CVSResponse.OK) {
0741:                    result = true;
0742:                    this .setUserName(userName);
0743:                    this .setPassword(this .isSSHServer() ? password : scrambled);
0744:                    response.appendStdout("Authentication of '" + userName
0745:                            + "' succeeded.\n");
0746:                } else {
0747:                    result = false;
0748:                    this .password = null;
0749:                    response.appendStdout("Authentication of '" + userName
0750:                            + "' failed.\n");
0751:                }
0752:
0753:                if (ui != null && response != null)
0754:                    ui.uiDisplayResponse(response);
0755:
0756:                if (response != null && !request.saveTempFiles)
0757:                    response.deleteTempFiles();
0758:
0759:                return result;
0760:            }
0761:
0762:            /**
0763:             * Given a repository path, which was not found in the
0764:             * pathTable, determine if the path is in the table if
0765:             * case is ignored. This is to support platforms which
0766:             * have case insensitive path names.
0767:             *
0768:             * @param subPath The path to check for in the table.
0769:             * @return The CVSEntry representing the path's directory.
0770:             */
0771:            CVSEntry getPathIgnoringCase(String subPath) {
0772:                Enumeration numer = this .pathTable.keys();
0773:
0774:                for (; numer.hasMoreElements();) {
0775:                    String key = (String) numer.nextElement();
0776:
0777:                    if (key.equalsIgnoreCase(subPath)) {
0778:                        return (CVSEntry) this .pathTable.get(key);
0779:                    }
0780:                }
0781:
0782:                return null;
0783:            }
0784:
0785:            /**
0786:             * Given a 'local directory' (in the protocol sense), get the
0787:             * corresponding directory CVSEntry. This method will return
0788:             * null if the directory hierarchy has not been "ensured" yet.
0789:             *
0790:             * @param localDir The directory's 'local directory' name.
0791:             */
0792:
0793:            public CVSEntry getDirEntryForLocalDir(String localDir) {
0794:                return this .getPathTableEntry(localDir);
0795:            }
0796:
0797:            private CVSEntry getPathTableEntry(String path) {
0798:                CVSEntry result = null;
0799:
0800:                result = (CVSEntry) this .pathTable.get(path);
0801:
0802:                if (result == null && !CVSCUtilities.caseSensitivePathNames()) {
0803:                    result = this .getPathIgnoringCase(path);
0804:                    if (CVSProject.deepDebug)
0805:                        CVSTracer.traceIf(true,
0806:                                "getPathTableEntry: CASE INsensitive TABLE CHECK\n"
0807:                                        + "   result    '"
0808:                                        + (result == null ? "(null)" : result
0809:                                                .getName())
0810:                                        + "'\n"
0811:                                        + "   reposirory  '"
0812:                                        + (result != null ? result
0813:                                                .getRepository() : "null")
0814:                                        + "'");
0815:                }
0816:
0817:                return result;
0818:            }
0819:
0820:            private CVSEntry reversePathTableEntry(String repository) {
0821:                CVSEntry result = null;
0822:
0823:                Enumeration numer = this .pathTable.keys();
0824:                for (boolean match = false; !match && numer.hasMoreElements();) {
0825:                    String localDir = (String) numer.nextElement();
0826:                    CVSEntry tblEntry = (CVSEntry) this .pathTable.get(localDir);
0827:
0828:                    if (CVSCUtilities.caseSensitivePathNames())
0829:                        match = repository.equals(tblEntry.getRepository());
0830:                    else
0831:                        match = repository.equalsIgnoreCase(tblEntry
0832:                                .getRepository());
0833:
0834:                    if (match)
0835:                        result = tblEntry;
0836:                }
0837:
0838:                if (CVSProject.deepDebug)
0839:                    CVSTracer.traceIf(true,
0840:                            "CVSProject.reversePathTableEntry:\n"
0841:                                    + "   repository = '"
0842:                                    + repository
0843:                                    + "'\n"
0844:                                    + "   RESULT =\n"
0845:                                    + (result == null ? "(null)" : result
0846:                                            .dumpString("   ")));
0847:
0848:                return result;
0849:            }
0850:
0851:            /**
0852:             * Guarentees that the repository contains the path specified.
0853:             * This will in turn invoke server commands to create the
0854:             * directories needed to make the path exist, so this can and
0855:             * will change the repository on the server. The repositoryPath
0856:             * is relative to the repository's root directory.
0857:             *
0858:             * @param ui The CVS User Interface to display the progress.
0859:             * @param localDirectory The <em>relative</em> path to ensure.
0860:             * @return A CVSResponse with the results of each directory 'add'.
0861:             */
0862:            public CVSResponse ensureRepositoryPath(CVSUserInterface ui,
0863:                    String localDirectory, CVSResponse resultResp) {
0864:                int index;
0865:                CVSEntry dirEntry;
0866:                CVSRequest request;
0867:                boolean result;
0868:
0869:                CVSTracer.traceIf(CVSProject.deepDebug,
0870:                        "CVSProject.ensureRepositoryPath: \n"
0871:                                + "   localDirectory '" + localDirectory + "'");
0872:
0873:                CVSEntryVector entries = new CVSEntryVector();
0874:
0875:                // Since we will be re-using this vector possibly many times,
0876:                // we can't keep appending. Thus, we append once here to fill
0877:                // in slots zero and one, then use setEntry() below
0878:                //
0879:                entries.appendEntry(null);
0880:                entries.appendEntry(null);
0881:
0882:                CVSTracer.traceIf(CVSProject.deepDebug,
0883:                        "ensureRepositoryPath: ROOT =\n   "
0884:                                + this .rootEntry.dumpString());
0885:
0886:                // The root directory has to exist by this point.
0887:                String repository = this .rootEntry.getRepository();
0888:                CVSTracer.traceIf(CVSProject.deepDebug,
0889:                        "ensureRepositoryPath: rootEntry repository = '"
0890:                                + repository + "'");
0891:
0892:                resultResp.setStatus(CVSResponse.OK);
0893:
0894:                CVSEntry parentEntry = this .rootEntry;
0895:
0896:                for (int offset = 2;;) {
0897:                    index = localDirectory.indexOf('/', offset);
0898:
0899:                    CVSTracer.traceIf(CVSProject.deepDebug,
0900:                            "ensureRepositoryPath: indexOf( '/'," + offset
0901:                                    + " ) = " + index);
0902:
0903:                    if (index < 0) {
0904:                        CVSTracer.traceIf(CVSProject.deepDebug,
0905:                                "ensureRepositoryPath: DONE w/ REMAINDER '"
0906:                                        + localDirectory.substring(offset)
0907:                                        + "'");
0908:                        break;
0909:                    }
0910:
0911:                    offset = index + 1;
0912:                    String localDir = localDirectory.substring(0, index + 1);
0913:                    dirEntry = this .getPathTableEntry(localDir);
0914:
0915:                    CVSTracer.traceIf(CVSProject.deepDebug,
0916:                            "ensureRepositoryPath: localDir '"
0917:                                    + localDir
0918:                                    + "' returns "
0919:                                    + (dirEntry == null ? "null" : dirEntry
0920:                                            .dumpString()));
0921:
0922:                    if (dirEntry != null) {
0923:                        if (CVSProject.deepDebug)
0924:                            CVSTracer.traceIf(true,
0925:                                    "ensureRepositoryPath: EXISTING DIRECTORY '"
0926:                                            + localDir + "'\n"
0927:                                            + "   localDir    '"
0928:                                            + dirEntry.getLocalDirectory()
0929:                                            + "'\n" + "   repository  '"
0930:                                            + dirEntry.getRepository() + "'");
0931:                        parentEntry = dirEntry;
0932:                        continue;
0933:                    }
0934:
0935:                    CVSTracer.traceIf(CVSProject.deepDebug,
0936:                            "ensureRepositoryPath: NEW CVS DIRECTORY '"
0937:                                    + localDir + "'\n"
0938:                                    + "   Parent LocalDirectory '"
0939:                                    + parentEntry.getLocalDirectory() + "'\n"
0940:                                    + "   Parent Repository     '"
0941:                                    + parentEntry.getRepository() + "'");
0942:
0943:                    request = new CVSRequest();
0944:
0945:                    String name = localDir.substring(0, localDir.length() - 1);
0946:                    index = name.lastIndexOf('/');
0947:                    if (index >= 0 && index < (name.length() - 1)) {
0948:                        name = name.substring(index + 1);
0949:                    }
0950:
0951:                    String rootDir = CVSCUtilities.ensureFinalSlash(this 
0952:                            .getRootDirectory());
0953:
0954:                    dirEntry = new CVSEntry();
0955:                    dirEntry.setName(name);
0956:                    dirEntry.setLocalDirectory(localDir);
0957:                    dirEntry.setRepository(parentEntry.getRepository() + "/"
0958:                            + name);
0959:                    // We need this next line to mark dirEntry as a directory!!
0960:                    dirEntry.setDirectoryEntryList(new CVSEntryVector());
0961:
0962:                    entries.setElementAt(parentEntry, 0);
0963:                    entries.setElementAt(dirEntry, 1);
0964:                    request.setEntries(entries);
0965:
0966:                    CVSTracer.traceIf(CVSProject.deepDebug,
0967:                            "ensureRepositoryPath: DIR ENTRY\n"
0968:                                    + "   Name       " + dirEntry.getName()
0969:                                    + "\n" + "   LocalDir   "
0970:                                    + dirEntry.getLocalDirectory() + "\n"
0971:                                    + "   Repository "
0972:                                    + dirEntry.getRepository());
0973:
0974:                    CVSTracer.traceIf(CVSProject.deepDebug,
0975:                            "ensureRepositoryPath: PARENT ENTRY\n"
0976:                                    + "   Name       " + parentEntry.getName()
0977:                                    + "\n" + "   LocalDir   "
0978:                                    + parentEntry.getLocalDirectory() + "\n"
0979:                                    + "   Reposirory "
0980:                                    + parentEntry.getRepository());
0981:
0982:                    request.execInCurDir = true;
0983:                    request.setDirEntry(parentEntry);
0984:
0985:                    request.sendEntries = true;
0986:                    request.sendArguments = true;
0987:                    request.sendEntryFiles = false;
0988:
0989:                    request.traceRequest = true; // CVSProject.overTraceRequest;
0990:                    request.traceResponse = true; // CVSProject.overTraceResponse;
0991:                    request.traceTCPData = true; // CVSProject.overTraceTCP;
0992:                    request.traceProcessing = true; // CVSProject.overTraceProcessing;
0993:
0994:                    request.allowGzipFileMode = this .allowGzipFileMode;
0995:                    request.gzipStreamLevel = this .gzipStreamLevel;
0996:
0997:                    request.setUserName(this .userName);
0998:                    request.setPServer(this .isPServer());
0999:
1000:                    // NOTE this.password is "correct" (scrambled for PServer
1001:                    //      mode, and not scrambled for SSH mode).
1002:                    if (this .isPServer() || this .isSSHServer()) {
1003:                        request.setPassword(this .password);
1004:                    }
1005:
1006:                    request.setPort(this .getClient().getPort());
1007:                    request.setHostName(this .getClient().getHostName());
1008:                    request.setRshProcess(this .getRshProcess());
1009:                    request.setPort(this .getConnectionPort());
1010:                    request.setConnectionMethod(this .getConnectionMethod());
1011:
1012:                    request.setRepository(this .repository);
1013:                    request.setRootRepository(this .rootEntry.getRepository());
1014:                    request.setRootDirectory(this .rootDirectory);
1015:                    request.setLocalDirectory(this .localRootDirectory);
1016:
1017:                    request.setServerCommand(this .getServerCommand());
1018:                    request.setSetVariables(this .setVars);
1019:                    this .establishNewDirSticky(request, dirEntry);
1020:                    this .establishStickys(request);
1021:                    this .establishStatics(request);
1022:
1023:                    request.setCommand("add");
1024:
1025:                    request
1026:                            .setUserInterface((ui == null) ? (CVSUserInterface) this 
1027:                                    : ui);
1028:                    request.includeNotifies = false;
1029:                    request.queueResponse = true;
1030:
1031:                    CVSArgumentVector arguments = new CVSArgumentVector();
1032:                    arguments.appendArgument(name);
1033:                    request.setArguments(arguments);
1034:
1035:                    CVSResponse response = client.processCVSRequest(request);
1036:
1037:                    response.deleteTempFiles(); // There shouldn't be any...
1038:
1039:                    String err = response.getStderr();
1040:                    if (err != null && err.length() > 0)
1041:                        resultResp.appendStderr(err);
1042:
1043:                    String out = response.getStdout();
1044:                    if (out != null && out.length() > 0)
1045:                        resultResp.appendStdout(out);
1046:
1047:                    if (response.getStatus() == CVSResponse.OK) {
1048:                        CVSTracer.traceIf(CVSProject.deepDebug,
1049:                                "ensureRepositoryPath: ensureEntryHierarchy( "
1050:                                        + dirEntry.getLocalDirectory() + ", "
1051:                                        + dirEntry.getRepository() + " )");
1052:
1053:                        this .ensureEntryHierarchy(dirEntry.getLocalDirectory(),
1054:                                dirEntry.getRepository());
1055:
1056:                        dirEntry = this .getPathTableEntry(localDir);
1057:                        if (dirEntry == null) {
1058:                            CVSTracer
1059:                                    .traceWithStack("WHAT?! ensured, but no pathTable entry '"
1060:                                            + localDir + "'?!?!");
1061:                        } else {
1062:                            dirEntry.setDirty(true);
1063:                        }
1064:
1065:                        this .ensureProperWorkingDirectory(
1066:                                this .localRootDirectory, localDir, true);
1067:                    } else {
1068:                        resultResp.setStatus(CVSResponse.ERROR);
1069:                        resultResp.appendStdOut(response.getStdout());
1070:                        resultResp.appendStdErr(response.getStderr());
1071:
1072:                        if (request.getUserInterface() != null)
1073:                            request.getUserInterface().uiDisplayResponse(
1074:                                    resultResp);
1075:
1076:                        CVSTracer.traceIf(true,
1077:                                "ensureRepositoryPath: ERROR! SERVER RESPONSE:\n"
1078:                                        + response.getStderr() + "\n"
1079:                                        + response.getStdout());
1080:
1081:                        break;
1082:                    }
1083:
1084:                    repository = repository + "/" + name;
1085:                }
1086:
1087:                return resultResp;
1088:            }
1089:
1090:            private String getStickyTagspec(CVSEntry entry) {
1091:                String result = "";
1092:
1093:                String rootPath = CVSProject.rootPathToAdminPath(this 
1094:                        .getLocalRootDirectory()
1095:                        + "/" + entry.getLocalPathName());
1096:
1097:                File stickyFile = new File(rootPath, "Tag");
1098:                if (stickyFile.exists()) {
1099:                    try {
1100:                        result = CVSCUtilities.readStringFile(stickyFile);
1101:                    } catch (IOException ex) {
1102:                        result = "";
1103:                    }
1104:
1105:                    if (!(result.startsWith("D") || result.startsWith("T")
1106:                    // REVIEW - Where does N enter the picture?!
1107:                    //          appears to be on "cvs add dir".
1108:                    || result.startsWith("N"))) {
1109:                        result = "";
1110:                    }
1111:                }
1112:
1113:                return result;
1114:            }
1115:
1116:            /**
1117:             * This methods deal with adding a new directory which is not
1118:             * yet in the repository, and yet, whose parent directory has
1119:             * a sticky tag set. We wish to "inherit" that tag...
1120:             */
1121:
1122:            public void establishNewDirSticky(CVSRequest request, CVSEntry entry) {
1123:                Hashtable stickys = request.getStickys();
1124:                if (stickys == null)
1125:                    stickys = new Hashtable();
1126:
1127:                String localDir = entry.getLocalDirectory();
1128:                String parentDir = CVSCUtilities.getLocalParent(localDir);
1129:
1130:                String rootPath = CVSProject.rootPathToAdminPath(this 
1131:                        .getLocalRootDirectory()
1132:                        + "/" + parentDir);
1133:
1134:                String tagSpec = "";
1135:                File stickyFile = new File(rootPath, "Tag");
1136:                if (stickyFile.exists()) {
1137:                    try {
1138:                        tagSpec = CVSCUtilities.readStringFile(stickyFile);
1139:                    } catch (IOException ex) {
1140:                        ex.printStackTrace();
1141:                    }
1142:                }
1143:
1144:                if (tagSpec.length() > 0) {
1145:                    rootPath = CVSProject.rootPathToAdminPath(this 
1146:                            .getLocalRootDirectory()
1147:                            + "/" + localDir);
1148:
1149:                    File adminDir = new File(rootPath);
1150:                    adminDir.mkdirs();
1151:                    stickyFile = new File(rootPath, "Tag");
1152:                    try {
1153:                        if (!stickyFile.exists()) {
1154:                            CVSCUtilities.writeStringFile(stickyFile, tagSpec);
1155:                        }
1156:                    } catch (IOException ex) {
1157:                        ex.printStackTrace();
1158:                    }
1159:                }
1160:
1161:                stickys.put(localDir, tagSpec);
1162:                stickys.put(parentDir, tagSpec);
1163:                request.setStickys(stickys);
1164:            }
1165:
1166:            public void establishStickys(CVSRequest request) {
1167:                Hashtable stickys = new Hashtable();
1168:
1169:                CVSEntryVector entries = request.getEntries();
1170:                for (int i = 0, sz = entries.size(); i < sz; ++i) {
1171:                    CVSEntry entry = (CVSEntry) entries.elementAt(i);
1172:                    String localDir = entry.getLocalDirectory();
1173:                    if (stickys.get(localDir) == null) {
1174:                        String tagSpec = this .getStickyTagspec(entry);
1175:                        stickys.put(localDir, tagSpec);
1176:                    }
1177:                }
1178:
1179:                if (stickys.size() > 0)
1180:                    request.setStickys(stickys);
1181:            }
1182:
1183:            private boolean isStaticDirectory(CVSEntry entry) {
1184:                String rootPath = CVSProject.rootPathToAdminPath(this 
1185:                        .getLocalRootDirectory()
1186:                        + "/" + entry.getLocalPathName());
1187:
1188:                File staticFile = new File(rootPath, "Entries.static");
1189:
1190:                return staticFile.exists();
1191:            }
1192:
1193:            public void establishStatics(CVSRequest request) {
1194:                Hashtable statics = new Hashtable();
1195:
1196:                CVSEntryVector entries = request.getEntries();
1197:                for (int i = 0, sz = entries.size(); i < sz; ++i) {
1198:                    CVSEntry entry = (CVSEntry) entries.elementAt(i);
1199:                    String localDir = entry.getLocalDirectory();
1200:                    if (statics.get(localDir) == null) {
1201:                        if (this .isStaticDirectory(entry))
1202:                            statics.put(localDir, "");
1203:                    }
1204:                }
1205:
1206:                if (statics.size() > 0)
1207:                    request.setStatics(statics);
1208:            }
1209:
1210:            public boolean performCVSRequest(CVSRequest request) {
1211:                return this .performCVSRequest(request, new CVSResponse());
1212:            }
1213:
1214:            public boolean performCVSRequest(CVSRequest request,
1215:                    CVSResponse response) {
1216:                boolean result = true;
1217:
1218:                request.setUserName(this .userName);
1219:                request.setPServer(this .isPServer());
1220:
1221:                if (this .isPServer() || this .isSSHServer()) {
1222:                    request.setPassword(this .password);
1223:                }
1224:
1225:                String rootRepository;
1226:                if (this .rootEntry != null) {
1227:                    rootRepository = this .rootEntry.getRepository();
1228:
1229:                    //
1230:                    // SPECIAL CASE
1231:                    // When we are asked to send the "module name" as an argment,
1232:                    // we have a problem. The module name "must" always be "."
1233:                    // (see CVSClient.c) to be correct. However, if the rootRepository
1234:                    // is sent from the root, then "." will be wrong. Thus, we will
1235:                    // override it here to make it right for this one case.
1236:                    //
1237:                    // NOTE Release 5.0.8: I do not know the source of this original
1238:                    //      "fix", but it breaks the "Update" module command (nothing
1239:                    //      happens at the top level). Removing this did not appear
1240:                    //      to break anything. So far...
1241:                    //
1242:                    /*
1243:                    if ( request.sendModule )
1244:                    	{
1245:                    	CVSEntry repEnt = this.rootEntry.getEntryList().getEntryAt(0);
1246:                    	CVSTracer.traceIf( this.deepDebug,
1247:                    		"CVSProject.performCVSRequest: APPLY MODULE NAME HACK\n"
1248:                    		+ "   repEnt =\n"
1249:                    		+ (repEnt==null?"NULL":repEnt.dumpString( "   " )) );
1250:
1251:                    	if ( repEnt != null )
1252:                    		{
1253:                    		rootRepository = repEnt.getRepository();
1254:                    		}
1255:                    	}
1256:                     */
1257:                } else {
1258:                    // This is 'checkout' or 'export' case.
1259:                    if (this .repository.equals("."))
1260:                        rootRepository = this .rootDirectory;
1261:                    else
1262:                        rootRepository = this .rootDirectory + "/"
1263:                                + this .repository;
1264:                }
1265:
1266:                request.setHostName(this .getClient().getHostName());
1267:                request.setRepository(this .repository);
1268:                request.setRootRepository(rootRepository);
1269:                request.setRootDirectory(this .rootDirectory);
1270:                request.setLocalDirectory(this .localRootDirectory);
1271:                request.setPort(this .getConnectionPort());
1272:                request.setConnectionMethod(this .getConnectionMethod());
1273:                request.setServerCommand(this .getServerCommand());
1274:                request.setRshProcess(this .getRshProcess());
1275:
1276:                request.setSetVariables(this .setVars);
1277:
1278:                this .establishStickys(request);
1279:
1280:                this .establishStatics(request);
1281:
1282:                if (request.includeNotifies) {
1283:                    this .includeNotifies(request);
1284:                }
1285:
1286:                if (!request.queueResponse)
1287:                    if (request.responseHandler == null)
1288:                        request.responseHandler = this ;
1289:
1290:                if (CVSProject.overTraceRequest)
1291:                    request.traceRequest = CVSProject.overTraceRequest;
1292:                if (CVSProject.overTraceResponse)
1293:                    request.traceResponse = CVSProject.overTraceResponse;
1294:                if (CVSProject.overTraceProcessing)
1295:                    request.traceProcessing = CVSProject.overTraceProcessing;
1296:                if (CVSProject.overTraceTCP)
1297:                    request.traceTCPData = CVSProject.overTraceTCP;
1298:
1299:                request.allowGzipFileMode = this .allowGzipFileMode;
1300:                request.gzipStreamLevel = this .gzipStreamLevel;
1301:
1302:                if (!request.verifyRequest()) {
1303:                    CVSLog
1304:                            .logMsg("CVSProject.performCVSRequest: BAD CVSRequest: '"
1305:                                    + request.getVerifyFailReason() + "'");
1306:                    return false;
1307:                } else {
1308:                    this .client.processCVSRequest(request, response);
1309:
1310:                    this .processCVSResponse(request, response);
1311:
1312:                    if (request.getCommand().equals("update")
1313:                            && (request.getArguments().containsArgument("-P")
1314:                                    || request.getArguments().containsArgument(
1315:                                            "-r") || request.getArguments()
1316:                                    .containsArgument("-D"))) {
1317:                        this .pruneEmptySubDirs(request.handleEntries);
1318:                    }
1319:
1320:                    if (request.getUserInterface() != null && response != null)
1321:                        request.getUserInterface().uiDisplayResponse(response);
1322:
1323:                    if (response != null && !request.saveTempFiles)
1324:                        response.deleteTempFiles();
1325:
1326:                    return (response.getStatus() == CVSResponse.OK);
1327:                }
1328:            }
1329:
1330:            public CVSEntry entryLineToEntry(String entryLine) {
1331:                CVSEntry entry = new CVSEntry();
1332:
1333:                try {
1334:                    entry.parseEntryLine(entryLine, true);
1335:                } catch (ParseException ex) {
1336:                    entry = null;
1337:                    CVSLog.traceMsg(ex, "CVSProject.entryFromEntryLine: ERROR "
1338:                            + "could not process entry line '" + entryLine);
1339:                }
1340:
1341:                return entry;
1342:            }
1343:
1344:            public File getLocalEntryFile(CVSEntry entry) {
1345:                File result = new File(CVSCUtilities
1346:                        .exportPath(this .localRootDirectory), CVSCUtilities
1347:                        .exportPath(entry.getFullPathName()));
1348:
1349:                return result;
1350:            }
1351:
1352:            /**
1353:             * Given a local-directory returned from the server,
1354:             * make sure the local-directory is in a format that
1355:             * jCVS can make use of (i.e., via the pathTable).
1356:             * Currently, the only case handled is when local-directory
1357:             * is './', which forces us to locate from pathTable.
1358:             *
1359:             * @param pathName The local-directory from the server.
1360:             * @param repository The repository the server sent with this local-directory.
1361:             * @return The normalized local-directory, or null if it does not exist.
1362:             */
1363:
1364:            public String normalizeLocalDirectory(String pathName,
1365:                    String repository) {
1366:                String result = pathName;
1367:
1368:                if (pathName.equals("./")) {
1369:                    CVSTracer.traceIf(this .deepDebug,
1370:                            "normalizeLocalDirectory: SPECIAL './' CASE.\n"
1371:                                    + "    pathName '" + pathName + "'\n"
1372:                                    + "  repository '" + repository + "'");
1373:
1374:                    // SPECIAL CASE
1375:                    // Here, we have a case where a command executed
1376:                    // in a subdirectory (or root), and instead of the
1377:                    // usual root-based local-directory, we get this.
1378:                    // We need to take the repository and reverse lookup
1379:                    // the local-directory.
1380:
1381:                    CVSEntry revEntry = this .reversePathTableEntry(repository);
1382:
1383:                    if (revEntry != null) {
1384:                        result = revEntry.getLocalDirectory();
1385:                    } else {
1386:                        result = null;
1387:                        CVSTracer.traceIf(true, "COULD NOT RESOLVE '"
1388:                                + pathName + "' with '" + repository + "'");
1389:                        CVSTracer.traceWithStack("COULD NOT RESOLVE '"
1390:                                + pathName + "' with '" + repository + "'");
1391:                    }
1392:                }
1393:
1394:                CVSTracer.traceIf(this .deepDebug,
1395:                        "normalizeLocalDirectory: RESULT '" + pathName
1396:                                + "' ---> '" + result + "'");
1397:
1398:                return result;
1399:            }
1400:
1401:            public CVSEntry createItemEntry(CVSResponseItem item) {
1402:                CVSEntry entry;
1403:                String entryLine = item.getEntriesLine();
1404:
1405:                CVSTracer.traceIf(this .deepDebug, "createItemEntry:\n"
1406:                        + "   item.getPathName    '" + item.getPathName()
1407:                        + "'\n" + "   item.repositoryName '"
1408:                        + item.getRepositoryName() + "'\n"
1409:                        + "   item.getEntriesLine '" + item.getEntriesLine()
1410:                        + "'");
1411:
1412:                // NOTE
1413:                // When the entryLine is null, all we are interested
1414:                // in is the name, localDirectory, and repository...
1415:                //
1416:                if (entryLine == null)
1417:                    entry = new CVSEntry();
1418:                else
1419:                    entry = this .entryLineToEntry(item.getEntriesLine());
1420:
1421:                if (entry != null) {
1422:                    String repos = item.getRepositoryName();
1423:                    int index = repos.lastIndexOf('/');
1424:
1425:                    if (index < 0) {
1426:                        CVSTracer
1427:                                .traceWithStack("CVSProject.createItemEntry: ERROR "
1428:                                        + "repository '"
1429:                                        + repos
1430:                                        + "' has no slash!");
1431:                        entry.setName(repos);
1432:                        entry.setRepository("");
1433:                    } else {
1434:                        entry.setName(repos.substring(index + 1));
1435:                        entry.setRepository(repos.substring(0, index));
1436:                    }
1437:
1438:                    String localDir = this .normalizeLocalDirectory(item
1439:                            .getPathName(), entry.getRepository());
1440:
1441:                    entry.setLocalDirectory(localDir);
1442:                }
1443:
1444:                return entry;
1445:            }
1446:
1447:            public boolean handleResponseItem(CVSRequest request,
1448:                    CVSResponse response, CVSResponseItem item) {
1449:                boolean result;
1450:
1451:                CVSTracer
1452:                        .traceIf(request.traceProcessing,
1453:                                "CVSProject.handleResponseItem:\n   "
1454:                                        + item.toString());
1455:
1456:                result = this .processResponseItem(request, response, item);
1457:
1458:                if (!request.saveTempFiles) {
1459:                    item.deleteFile();
1460:                }
1461:
1462:                return result;
1463:            }
1464:
1465:            public boolean processCVSResponse(CVSRequest request,
1466:                    CVSResponse response) {
1467:                int idx;
1468:                boolean ok;
1469:                CVSEntry entry = null;
1470:                boolean result = true;
1471:                File localFile = null;
1472:                CVSResponseItem item = null;
1473:
1474:                if (response == null)
1475:                    return true;
1476:
1477:                // NOTE
1478:                // We process the item list, EVEN when !queueResponse,
1479:                // since the responseHandler may have queued some of the
1480:                // response items for processing here!!!
1481:                //
1482:                CVSRespItemVector items = response.getItemList();
1483:
1484:                for (idx = 0; result && idx < items.size(); ++idx) {
1485:                    item = items.itemAt(idx);
1486:
1487:                    CVSTracer.traceIf(request.traceProcessing,
1488:                            "CVSResponse: item[" + idx + "] type '"
1489:                                    + item.getType() + "'");
1490:
1491:                    result = this .processResponseItem(request, response, item);
1492:                }
1493:
1494:                if (response.getStatus() != CVSResponse.OK) {
1495:                    if (request.traceProcessing)
1496:                        CVSTracer.traceIf(true,
1497:                                "CVSProject.processCVSResponse: ERROR errorCode '"
1498:                                        + response.getErrorCode()
1499:                                        + "' errorText '"
1500:                                        + response.getErrorText() + "'");
1501:
1502:                    if (response.getErrorCode().length() > 0
1503:                            || response.getErrorText().length() > 0) {
1504:                        response.appendStderr("\nError Code '"
1505:                                + response.getErrorCode() + "'" + " Message '"
1506:                                + response.getErrorText() + "'\n");
1507:                    }
1508:                } else {
1509:                    CVSTracer.traceIf(request.traceProcessing,
1510:                            "CVSProject.processCVSResponse: OK");
1511:
1512:                    if (request.handleEntries) {
1513:                        this .writeAdminFiles();
1514:                    }
1515:                }
1516:
1517:                // REVIEW - Should error results with empty code and text
1518:                //          be ignored by default? This is the 'Diff' case!
1519:                //
1520:                //          Actually, I think I want to special case 'diff'
1521:                //          here and use the 'ERROR' status to indicate that
1522:                //          there were 'no differences'. I think I can check
1523:                //          for an empty 'code' or 'message' to confirm that
1524:                //          it is 'no diffs' case and not 'some diff error'.
1525:
1526:                if (request.ignoreResult) {
1527:                    response.setStatus(CVSResponse.OK);
1528:                }
1529:
1530:                return result;
1531:            }
1532:
1533:            private boolean processResponseItem(CVSRequest request,
1534:                    CVSResponse response, CVSResponseItem item) {
1535:                int idx;
1536:                boolean ok;
1537:                CVSEntry entry = null;
1538:                boolean result = true;
1539:                File localFile = null;
1540:
1541:                //
1542:                // HACK
1543:                // NOTE
1544:                //
1545:                // This is a special hack to accomodate the one compromise we needed
1546:                // to make to get all of the path handling to work. We wrote the one
1547:                // directive that
1548:                //
1549:                //      ALL LOCAL DIRECTORY NAMES MUST BEGIN WITH "./"
1550:                //
1551:                // This make every case of the hideous paths returned by the server
1552:                // work for us, since we are not like UNIX which works in a strickly
1553:                // "relative" sense. We work from an "absolute" sense, for better or
1554:                // worse...
1555:                //
1556:                // SPECIAL CASE
1557:                //
1558:                // There are times when the server will return a response item with
1559:                // a repositry path ending with "./". This is usually our bad in the
1560:                // protocol, but it is easy to catch and fix, so...
1561:                //
1562:                if (item.getPathName().endsWith("./")) {
1563:                    item.setPathName(item.getPathName().substring(0,
1564:                            item.getPathName().length() - 2));
1565:
1566:                    CVSTracer.traceIf(this .deepDebug,
1567:                            "\nPROCESSResponseItem: STRIPPED FINAL './' CASE\n"
1568:                                    + "   item.pathName = '"
1569:                                    + item.getPathName() + "'");
1570:                }
1571:
1572:                if (!item.getPathName().startsWith("./")) {
1573:                    String itemRepos = item.getRepositoryName();
1574:                    int slashIdx = itemRepos.lastIndexOf("/");
1575:                    if (slashIdx != -1) {
1576:                        itemRepos = itemRepos.substring(0, slashIdx);
1577:                    }
1578:
1579:                    CVSEntry hackEntry = this .reversePathTableEntry(itemRepos);
1580:
1581:                    CVSTracer.traceIf(this .deepDebug,
1582:                            "\nPROCESSResponseItem: APPLY ITEM PATHNAME HACK\n"
1583:                                    + "   item.pathName = '"
1584:                                    + item.getPathName()
1585:                                    + "'\n"
1586:                                    + "   item.repos    = '"
1587:                                    + item.getRepositoryName()
1588:                                    + "'\n"
1589:                                    + " lookup repos    = '"
1590:                                    + itemRepos
1591:                                    + "'\n"
1592:                                    + "   pathTable.entry:\n"
1593:                                    + (hackEntry == null ? "   NULL"
1594:                                            : hackEntry.dumpString("   ")));
1595:
1596:                    if (hackEntry != null) {
1597:                        item.setPathName(hackEntry.getLocalDirectory());
1598:                        CVSTracer
1599:                                .traceIf(this .deepDebug,
1600:                                        "\nPROCESSResponseItem: ITEM PATH set to '"
1601:                                                + hackEntry.getLocalDirectory()
1602:                                                + "'\n");
1603:                    } else {
1604:                        //
1605:                        // NOTE
1606:                        // If we did not find the repository pathname, then this item
1607:                        // is something we have never seen before. This should ONLY
1608:                        // happen during things like checkout, where the tree does not
1609:                        // exist yet. In these cases. prepending "./" to the local
1610:                        // directory appears to be the correct answer.
1611:                        //
1612:                        item.setPathName("./" + item.getPathName());
1613:                        CVSTracer.traceIf(this .deepDebug,
1614:                                "\nPROCESSResponseItem: NO PATH TABLE ENTRY, PREFIX w/ './'\n"
1615:                                        + "   ITEM PATH set to '"
1616:                                        + item.getPathName() + "'");
1617:                    }
1618:                }
1619:
1620:                CVSTracer.traceIf(this .deepDebug, "PROCESSResponseItem:\n"
1621:                        + "   item.getType        '" + item.getType() + "'\n"
1622:                        + "   item.getPathName    '" + item.getPathName()
1623:                        + "'\n" + "   item.repositoryName '"
1624:                        + item.getRepositoryName() + "'\n"
1625:                        + "   item.getModeLine    '" + item.getModeLine()
1626:                        + "'\n" + "   item.getEntriesLine '"
1627:                        + item.getEntriesLine() + "'");
1628:
1629:                switch (item.getType()) {
1630:                case CVSResponseItem.CHECKED_IN:
1631:                    // Checked-in implies the file is up-to-date
1632:                    CVSTracer.traceIf(request.traceProcessing,
1633:                            "CHECKED_IN: pathName '" + item.getPathName()
1634:                                    + "'\n   repository "
1635:                                    + item.getRepositoryName()
1636:                                    + "'\n   entryLine "
1637:                                    + item.getEntriesLine());
1638:
1639:                    if (request.handleEntries) {
1640:                        entry = this .createItemEntry(item);
1641:                        if (entry != null) {
1642:                            CVSTracer.traceIf(request.traceProcessing,
1643:                                    "CHECKED_IN: entry '" + entry.getFullName()
1644:                                            + "'");
1645:
1646:                            localFile = this .getEntryFile(entry);
1647:
1648:                            entry.setTimestamp(localFile);
1649:
1650:                            this .updateEntriesItem(entry);
1651:                        }
1652:                    }
1653:                    break;
1654:
1655:                case CVSResponseItem.NOTIFIED:
1656:                    CVSTracer.traceIf(request.traceProcessing,
1657:                            "NOTIFIED: pathName '" + item.getPathName()
1658:                                    + "'\n          repository '"
1659:                                    + item.getRepositoryName() + "'");
1660:
1661:                    this .processNotified(item);
1662:                    break;
1663:
1664:                case CVSResponseItem.CHECKSUM:
1665:                    // UNDONE
1666:                    break;
1667:
1668:                case CVSResponseItem.COPY_FILE:
1669:                    CVSTracer.traceIf(request.traceProcessing,
1670:                            "COPY-FILE: pathName '" + item.getPathName()
1671:                                    + "'\n           newName '"
1672:                                    + item.getNewName() + "'");
1673:
1674:                    //
1675:                    // UNDONE - it would be nice if we had a better
1676:                    //          error report, but we do not have the
1677:                    //          response object available deep in the
1678:                    //          method call, and we do not throw an
1679:                    //          exception, which may have been a better
1680:                    //          choice than returning false.... (duh)
1681:                    //
1682:                    if (!this .performCopyFile(item)) {
1683:                        response.appendStderr("ERROR copying file '"
1684:                                + item.getPathName() + "' to '"
1685:                                + item.getNewName() + "'.");
1686:                    }
1687:                    break;
1688:
1689:                case CVSResponseItem.CLEAR_STICKY:
1690:                    CVSTracer.traceIf(request.traceProcessing,
1691:                            "Clear-sticky: pathName '" + item.getPathName()
1692:                                    + "'\n");
1693:                    this .setSticky(item, false, request.handleEntries);
1694:                    break;
1695:
1696:                case CVSResponseItem.SET_STICKY:
1697:                    CVSTracer.traceIf(request.traceProcessing,
1698:                            "Set-sticky: pathName '" + item.getPathName()
1699:                                    + "'\n");
1700:                    this .setSticky(item, true, request.handleEntries);
1701:                    break;
1702:
1703:                case CVSResponseItem.CLEAR_STATIC_DIR:
1704:                    CVSTracer.traceIf(request.traceProcessing,
1705:                            "Clear-static-directory: pathName '"
1706:                                    + item.getPathName() + "'\n");
1707:                    this .setStaticDirectory(item, false, request.handleEntries);
1708:                    break;
1709:
1710:                case CVSResponseItem.SET_STATIC_DIR:
1711:                    CVSTracer.traceIf(request.traceProcessing,
1712:                            "Set-static-directory: pathName '"
1713:                                    + item.getPathName() + "'\n");
1714:                    this .setStaticDirectory(item, true, request.handleEntries);
1715:                    break;
1716:
1717:                case CVSResponseItem.MODULE_EXPANSION:
1718:                    // UNDONE
1719:                    break;
1720:
1721:                case CVSResponseItem.NEW_ENTRY:
1722:                    // New-entry implies the file is still NOT up-to-date
1723:                    CVSTracer.traceIf(request.traceProcessing,
1724:                            "NEW_ENTRY: name '" + item.getPathName()
1725:                                    + "' entryLine '" + item.getEntriesLine()
1726:                                    + "'");
1727:
1728:                    if (request.handleEntries) {
1729:                        entry = this .createItemEntry(item);
1730:                        if (entry != null) {
1731:                            this .updateEntriesItem(entry);
1732:                        }
1733:                    }
1734:                    break;
1735:
1736:                case CVSResponseItem.REMOVED:
1737:                    CVSTracer.traceIf(request.traceProcessing, "REMOVED: "
1738:                            + item.getPathName());
1739:
1740:                    if (request.handleEntries) {
1741:                        this .removeEntriesItem(item);
1742:                    }
1743:                    break;
1744:
1745:                case CVSResponseItem.REMOVE_ENTRY:
1746:                    CVSTracer.traceIf(request.traceProcessing, "REMOVE_ENTRY: "
1747:                            + item.getPathName());
1748:
1749:                    if (request.handleEntries) {
1750:                        this .removeEntriesItem(item);
1751:                    }
1752:                    break;
1753:
1754:                case CVSResponseItem.VALID_REQUESTS:
1755:                    // clients don't implement this.
1756:                    break;
1757:
1758:                case CVSResponseItem.SET_CHECKIN_PROG:
1759:                    if (request.handleFlags) {
1760:                        request.setCheckInProgram(item.getPathName());
1761:                    }
1762:                    break;
1763:
1764:                case CVSResponseItem.SET_UPDATE_PROG:
1765:                    if (request.handleFlags) {
1766:                        request.setUpdateProgram(item.getPathName());
1767:                    }
1768:                    break;
1769:
1770:                case CVSResponseItem.PATCHED:
1771:                    CVSTracer.traceIf(true,
1772:                            "CVSProject.CVSResponseItem.PATCHED '"
1773:                                    + item.getEntriesLine() + "' "
1774:                                    + "PATCHED currently unimplemented.\n"
1775:                                    + "WE SHOULD NOT BE GETTING THIS!!!");
1776:
1777:                    response
1778:                            .appendStderr("The 'Patched' response is not implemented:\n"
1779:                                    + "    '" + item.getEntriesLine() + "'");
1780:                    break;
1781:
1782:                case CVSResponseItem.CREATED:
1783:                case CVSResponseItem.MERGED:
1784:                case CVSResponseItem.UPDATED:
1785:                case CVSResponseItem.UPDATE_EXISTING:
1786:                    if (request.handleUpdated) {
1787:                        String cmdName = (item.getType() == CVSResponseItem.CREATED ? "Created"
1788:                                : (item.getType() == CVSResponseItem.MERGED ? "Merged"
1789:                                        : (item.getType() == CVSResponseItem.UPDATED ? "Updated"
1790:                                                : "Updated existing")));
1791:
1792:                        entry = this .createItemEntry(item);
1793:                        if (entry != null) {
1794:                            // We have to save this state, since the set
1795:                            // of the timestamp from the local file will
1796:                            // clear it in the entry.
1797:                            boolean isInConflict = entry.isInConflict();
1798:
1799:                            ok = this .ensureEntryHierarchy(item.getPathName(),
1800:                                    item.getRepositoryPath());
1801:
1802:                            localFile = this .getEntryFile(entry);
1803:
1804:                            if (ok) {
1805:                                ok = this .ensureLocalTree(localFile,
1806:                                        request.handleEntries);
1807:                            }
1808:
1809:                            if (localFile.exists()) {
1810:                                entry.setTimestamp(localFile);
1811:                            }
1812:
1813:                            if (ok) {
1814:                                request.getUserInterface()
1815:                                        .uiDisplayProgressMsg(
1816:                                                cmdName + " local file '"
1817:                                                        + localFile.getPath()
1818:                                                        + "'.");
1819:
1820:                                // UNDONE try/catch for better messaging!!!
1821:                                ok = this .updateLocalFile(item, entry,
1822:                                        localFile);
1823:                            }
1824:
1825:                            if (ok) {
1826:                                if (isInConflict) {
1827:                                    entry.setConflict(localFile);
1828:                                } else if (item.getType() == CVSResponseItem.MERGED) {
1829:                                    entry.setTimestamp("Result of merge");
1830:                                } else {
1831:                                    entry.setTimestamp(localFile);
1832:                                }
1833:
1834:                                if (request.handleEntries) {
1835:                                    this .updateEntriesItem(entry);
1836:                                }
1837:                            } else {
1838:                                CVSLog
1839:                                        .logMsg("CVSResponse: ERROR merging local file '"
1840:                                                + entry.getFullName() + "'");
1841:
1842:                                response
1843:                                        .appendStderr("ERROR failed updating local file '"
1844:                                                + localFile.getPath() + "'.");
1845:
1846:                                result = false;
1847:                            }
1848:                        } else {
1849:                            CVSLog
1850:                                    .logMsg("CVSResponse: ERROR creating item entry '"
1851:                                            + item.toString() + "'");
1852:                            result = false;
1853:                        }
1854:                    }
1855:                    break;
1856:
1857:                } // end of switch ( item type )
1858:
1859:                return result;
1860:            }
1861:
1862:            public boolean performCopyFile(CVSResponseItem item) {
1863:                boolean result = true;
1864:
1865:                CVSEntry entry = this .createItemEntry(item);
1866:
1867:                if (entry != null) {
1868:                    File fromFile = this .getEntryFile(entry);
1869:
1870:                    entry.setName(item.getNewName());
1871:
1872:                    File toFile = this .getEntryFile(entry);
1873:
1874:                    if (fromFile.exists()) {
1875:                        // REVIEW - with Jim Kingdon
1876:                        // wouldn't it simply be more efficient to rename?
1877:                        // boolean err = fromFile.renameTo( toFile );
1878:                        result = this .copyFileRaw(fromFile, toFile, item
1879:                                .isGZIPed());
1880:
1881:                        if (!result) {
1882:                            CVSLog
1883:                                    .logMsg("CVSProject.performCopyFile: ERROR renaming '"
1884:                                            + fromFile.getPath()
1885:                                            + "' to '"
1886:                                            + toFile.getPath() + "'");
1887:                        }
1888:                    } else {
1889:                        CVSLog.logMsg("CVSProject.performCopyFile: file '"
1890:                                + fromFile.getPath() + "' does not exist!");
1891:                    }
1892:                } else {
1893:                    CVSTracer.traceWithStack("WHY is this entry NULL?! item '"
1894:                            + item.toString() + "'");
1895:                }
1896:
1897:                return result;
1898:            }
1899:
1900:            public boolean setSticky(CVSResponseItem item, boolean isSet,
1901:                    boolean writeFile) {
1902:                boolean result;
1903:
1904:                String localDir = this .normalizeLocalDirectory(item
1905:                        .getPathName(), item.getRepositoryPath());
1906:
1907:                result = this .ensureEntryHierarchy(localDir, item
1908:                        .getRepositoryPath());
1909:
1910:                if (result) {
1911:                    result = this .ensureProperWorkingDirectory(
1912:                            this .localRootDirectory, localDir, writeFile);
1913:                }
1914:
1915:                if (result && writeFile) {
1916:                    CVSEntry entry = this .createItemEntry(item);
1917:                    if (entry != null) {
1918:                        entry.setName("CVS/Tag");
1919:                        File file = this .getEntryFile(entry);
1920:
1921:                        if (isSet) {
1922:                            if (!file.exists()) {
1923:                                try {
1924:                                    CVSCUtilities.writeStringFile(file, item
1925:                                            .getTagSpec());
1926:                                } catch (IOException ex) {
1927:                                    CVSTracer
1928:                                            .traceWithStack("ERROR writing sticky tag file '"
1929:                                                    + file.getPath()
1930:                                                    + "', "
1931:                                                    + ex.getMessage());
1932:                                }
1933:                            }
1934:                        } else {
1935:                            if (file.exists()) {
1936:                                file.delete();
1937:                            }
1938:                        }
1939:                    }
1940:                } else if (!result) {
1941:                    CVSTracer.traceWithStack("ensureEntryHierarchy( '"
1942:                            + item.getPathName() + "', '"
1943:                            + item.getRepositoryPath() + "' ) FAILED");
1944:                }
1945:
1946:                return result;
1947:            }
1948:
1949:            public boolean setStaticDirectory(CVSResponseItem item,
1950:                    boolean isSet, boolean writeFile) {
1951:                boolean result;
1952:
1953:                result = this .ensureEntryHierarchy(item.getPathName(), item
1954:                        .getRepositoryPath());
1955:
1956:                if (result) {
1957:                    result = this .ensureProperWorkingDirectory(
1958:                            this .localRootDirectory, this 
1959:                                    .normalizeLocalDirectory(
1960:                                            item.getPathName(), item
1961:                                                    .getRepositoryPath()),
1962:                            writeFile);
1963:                }
1964:
1965:                if (result && writeFile) {
1966:                    CVSEntry entry = this .createItemEntry(item);
1967:                    if (entry != null) {
1968:                        entry.setName("CVS/Entries.static");
1969:                        File file = this .getEntryFile(entry);
1970:
1971:                        if (isSet) {
1972:                            if (!file.exists()) {
1973:                                CVSCUtilities.createEmptyFile(file);
1974:                            }
1975:                        } else {
1976:                            if (file.exists()) {
1977:                                file.delete();
1978:                            }
1979:                        }
1980:                    }
1981:                } else if (!result) {
1982:                    CVSTracer.traceWithStack("ensureEntryHierarchy( '"
1983:                            + item.getPathName() + "', '"
1984:                            + item.getRepositoryPath() + "' ) FAILED");
1985:                }
1986:
1987:                return result;
1988:            }
1989:
1990:            public CVSNotifyItem parseNotifyLine(String notifyLine) {
1991:                CVSNotifyItem result = null;
1992:
1993:                String notType = notifyLine.substring(0, 1);
1994:                notifyLine = notifyLine.substring(1);
1995:
1996:                StringTokenizer toker = new StringTokenizer(notifyLine, "\t");
1997:
1998:                int count = toker.countTokens();
1999:
2000:                if (count > 3) {
2001:                    String name = null;
2002:                    String time = null;
2003:                    String host = null;
2004:                    String wdir = null;
2005:                    String watches = null;
2006:
2007:                    try {
2008:                        name = toker.nextToken();
2009:                        time = toker.nextToken();
2010:                        host = toker.nextToken();
2011:                        wdir = toker.nextToken();
2012:                    } catch (NoSuchElementException ex) {
2013:                        name = null;
2014:                    }
2015:
2016:                    try {
2017:                        watches = toker.nextToken();
2018:                    } catch (NoSuchElementException ex) {
2019:                        watches = null;
2020:                    }
2021:
2022:                    if (name != null && time != null && host != null
2023:                            && wdir != null) {
2024:                        CVSEntry entry = (CVSEntry) this .pathTable.get(wdir);
2025:
2026:                        if (entry != null) {
2027:                            result = new CVSNotifyItem(notType, name, time,
2028:                                    host, wdir,
2029:                                    (watches == null ? "" : watches), entry
2030:                                            .getRepository());
2031:                        }
2032:                    }
2033:                }
2034:
2035:                return result;
2036:            }
2037:
2038:            protected boolean processNotified(CVSResponseItem item) {
2039:                boolean result = true;
2040:                BufferedReader read;
2041:                PrintWriter write;
2042:                String inline;
2043:
2044:                CVSEntry entry = this .createItemEntry(item);
2045:
2046:                String itemPath = entry.getFullName();
2047:
2048:                String fileName = CVSProject.getAdminNotifyPath(CVSProject
2049:                        .rootPathToAdminPath(this .getLocalRootPath()));
2050:
2051:                File notFile = new File(fileName);
2052:                File tmpFile = new File(fileName + ".tmp");
2053:
2054:                try {
2055:                    read = new BufferedReader(new FileReader(notFile));
2056:                    write = new PrintWriter(new FileWriter(tmpFile));
2057:                } catch (IOException ex) {
2058:                    String msg = "ERROR opening Notification file '" + fileName
2059:                            + "' for Notified response.";
2060:                    CVSLog.logMsg(msg);
2061:                    CVSTracer.traceWithStack(msg);
2062:                    return false;
2063:                }
2064:
2065:                int count = 0;
2066:                for (boolean chk = true;;) {
2067:                    try {
2068:                        inline = read.readLine();
2069:                    } catch (IOException ex) {
2070:                        String msg = "ERROR reading Notification file "
2071:                                + "during Notified response.";
2072:                        CVSLog.logMsg(msg);
2073:                        CVSTracer.traceWithStack(msg);
2074:                        inline = null;
2075:                    }
2076:
2077:                    if (inline == null)
2078:                        break;
2079:
2080:                    if (!chk) {
2081:                        write.println(inline);
2082:                        count++;
2083:                    } else {
2084:                        CVSNotifyItem notifyItem = this .parseNotifyLine(inline);
2085:
2086:                        if (notifyItem != null) {
2087:                            String fullName = notifyItem.getWorkingDirectory()
2088:                                    + notifyItem.getName();
2089:
2090:                            if (!itemPath.equals(fullName)) {
2091:                                write.println(inline);
2092:                                chk = false;
2093:                                count++;
2094:                            }
2095:                        } else {
2096:                            CVSLog.logMsg("ERROR, bad line in 'CVS/Notify':\n"
2097:                                    + "   File: '" + fileName + "'\n"
2098:                                    + "   Line: " + inline);
2099:                        }
2100:                    }
2101:                }
2102:
2103:                try {
2104:                    read.close();
2105:                } catch (IOException ex) {
2106:                }
2107:
2108:                write.flush();
2109:                write.close();
2110:
2111:                if (result) {
2112:                    result = notFile.delete();
2113:                    if (result) {
2114:                        if (count > 0)
2115:                            result = tmpFile.renameTo(notFile);
2116:                        else
2117:                            tmpFile.delete();
2118:                    }
2119:                }
2120:
2121:                return result;
2122:            }
2123:
2124:            public String readRootDirectory(File rootFile) {
2125:                String result = null;
2126:                try {
2127:                    result = CVSCUtilities.readStringFile(rootFile);
2128:                } catch (IOException ex) {
2129:                    result = null;
2130:                }
2131:
2132:                return result;
2133:            }
2134:
2135:            public String readRepository(File reposFile) {
2136:                String result = null;
2137:                try {
2138:                    result = CVSCUtilities.readStringFile(reposFile);
2139:                } catch (IOException ex) {
2140:                    result = null;
2141:                }
2142:
2143:                return result;
2144:            }
2145:
2146:            /**
2147:             *
2148:             * @param repository The server's repository pathname for the root.
2149:             */
2150:            public void establishRootEntry(String repository) {
2151:                if (CVSProject.deepDebug)
2152:                    CVSTracer.traceIf(true, "CVSProject.establishRootEntry: "
2153:                            + "repository  '" + repository + "'");
2154:
2155:                CVSEntry rootEntry = new CVSEntry();
2156:
2157:                rootEntry.setDirty(true);
2158:                rootEntry.setName(".");
2159:                rootEntry.setRepository(repository);
2160:                rootEntry.setLocalDirectory("./");
2161:
2162:                // We need to set the Entry List to mark this as a directory.
2163:                rootEntry.setDirectoryEntryList(new CVSEntryVector());
2164:
2165:                this .pathTable.put(rootEntry.getLocalDirectory(), rootEntry);
2166:
2167:                if (CVSProject.deepDebug)
2168:                    CVSTracer.traceIf(true,
2169:                            "CVSProject.establishRootEntry: ROOT ESTABLISHED:\n"
2170:                                    + rootEntry.dumpString("   "));
2171:
2172:                this .rootEntry = rootEntry;
2173:            }
2174:
2175:            public void openProject(File localRootFile) throws IOException {
2176:                String repositoryStr;
2177:                String rootDirectoryStr;
2178:
2179:                if (this .deepDebug)
2180:                    CVSTracer.traceIf(true,
2181:                            "CVSProject.openProject: OPEN PROJECT '"
2182:                                    + localRootFile.getPath() + "'");
2183:
2184:                File adminDirFile = new File(localRootFile.getPath(), "CVS");
2185:
2186:                if (this .deepDebug)
2187:                    CVSTracer.traceIf(true,
2188:                            "CVSProject.openProject: adminDirFile '"
2189:                                    + adminDirFile.getPath() + "'");
2190:
2191:                if (!adminDirFile.exists())
2192:                    throw new IOException("admin directory '"
2193:                            + adminDirFile.getPath() + "' does not exist");
2194:
2195:                String rootPath = CVSProject.getAdminRootPath(CVSCUtilities
2196:                        .importPath(adminDirFile.getPath()));
2197:
2198:                File adminRootFile = new File(CVSCUtilities
2199:                        .exportPath(rootPath));
2200:
2201:                if (this .deepDebug)
2202:                    CVSTracer.traceIf(true,
2203:                            "CVSProject.openProject: adminRootFile '"
2204:                                    + adminRootFile.getPath() + "'");
2205:
2206:                if (!adminRootFile.exists())
2207:                    throw new IOException("admin Root file '"
2208:                            + adminRootFile.getPath() + "' does not exist");
2209:
2210:                String reposPath = CVSProject
2211:                        .getAdminRepositoryPath(adminDirFile.getPath());
2212:
2213:                File adminRepositoryFile = new File(reposPath);
2214:
2215:                if (this .deepDebug)
2216:                    CVSTracer.traceIf(true,
2217:                            "CVSProject.openProject: adminRepositoryFile '"
2218:                                    + adminRepositoryFile.getPath() + "'");
2219:
2220:                if (!adminRepositoryFile.exists())
2221:                    throw new IOException("admin Repository file '"
2222:                            + adminRepositoryFile.getPath()
2223:                            + "' does not exist");
2224:
2225:                rootDirectoryStr = this .readRootDirectory(adminRootFile);
2226:                if (rootDirectoryStr == null)
2227:                    throw new IOException("could not read admin Root file '"
2228:                            + adminRootFile.getPath() + "'");
2229:
2230:                repositoryStr = this .readRepository(adminRepositoryFile);
2231:                if (repositoryStr == null)
2232:                    throw new IOException(
2233:                            "could not read admin Repository file '"
2234:                                    + adminRepositoryFile.getPath() + "'");
2235:
2236:                if (this .deepDebug)
2237:                    CVSTracer.traceIf(true,
2238:                            "CVSProject.openProject: Read Admin directory\n"
2239:                                    + "   rootPath   '" + rootPath + "'\n"
2240:                                    + "   reposPath  '" + reposPath + "'\n"
2241:                                    + "   rootDirStr '" + rootDirectoryStr
2242:                                    + "'\n" + "   reposStr   '" + repositoryStr
2243:                                    + "'");
2244:
2245:                this .projectDef = new CVSProjectDef(rootDirectoryStr,
2246:                        repositoryStr);
2247:
2248:                if (!this .projectDef.isValid())
2249:                    throw new IOException(
2250:                            "could not parse project specification, "
2251:                                    + this .projectDef.getReason());
2252:
2253:                this .isPServer = this .projectDef.isPServer();
2254:                this .connMethod = this .projectDef.getConnectMethod();
2255:                this .userName = this .projectDef.getUserName();
2256:                this .getClient().setHostName(this .projectDef.getHostName());
2257:
2258:                rootDirectoryStr = this .projectDef.getRootDirectory();
2259:
2260:                //
2261:                // REVIEW
2262:                // Should I not remove the check for the '/' or 'C:/'
2263:                // at the beginning and just make the "starts with root
2264:                // directory" check in stead, and then if that does not
2265:                // match, see if the string starts with 'C:/' and if not
2266:                // assume relative at that point? Would that not make
2267:                // the code less dependent on what are valid "starts"?
2268:                //
2269:                // The previous check, that is started with '/', does
2270:                // not work for the case of a Win32 server, since it
2271:                // will have a root such as 'C:/cvs'. Thus, we now
2272:                // check for "starts with /", as well as "starts with
2273:                // drive letter colon slash".
2274:                //
2275:                // Thanks to Manfred Usselmann <Usselmann.M@icg-online.de>
2276:                // for these patches.
2277:                //
2278:                // OLD CODE:
2279:                // if ( repositoryStr.startsWith( "/" ) )
2280:                //
2281:                // Contributed CODE:
2282:                // char ch0 = repositoryStr.charAt(0);
2283:                // char ch1 = repositoryStr.charAt(1);
2284:                // char ch2 = repositoryStr.charAt(2);
2285:                // if ( ch0 == '/'
2286:                // 		// IF there a colon for the drive letter
2287:                // 		|| ( ch1 == ':'
2288:                // 			// AND there is a valid drive letter
2289:                // 			&& ( ( ch0 >= 'a' && ch0 <= 'z' )
2290:                // 				|| ( ch0 >= 'A' && ch0 <= 'Z' ) )
2291:                // 			// AND there is a slash or backslash
2292:                // 			&& ( ch2 == '/' || ch2 == '\\' ) ) )
2293:                // 	{
2294:                // 	if ( ! repositoryStr.startsWith( rootDirectoryStr ) )
2295:                // 		{
2296:                // 		throw new IOException
2297:                // 			( "full repository path '" + repositoryStr
2298:                // 				+ "' does not start with Root path '"
2299:                // 				+ rootDirectoryStr + "'" );
2300:                // 		}
2301:                // 	}
2302:                // else
2303:                // 	{
2304:                // 	// The relative pathname case, prepend with the root.
2305:                // 	repositoryStr = rootDirectoryStr + "/" + repositoryStr;
2306:                // 	}
2307:                //
2308:
2309:                if (repositoryStr.startsWith(rootDirectoryStr)) {
2310:                    // The full pathname case. No adjustment needed.
2311:                } else {
2312:                    // The relative pathname case, prepend with the root.
2313:                    repositoryStr = rootDirectoryStr + "/" + repositoryStr;
2314:                }
2315:
2316:                //
2317:                // REVIEW
2318:                // UNDONE - need 'computeParentDirectory()' here.
2319:                //          File.getParent() does not seem to work.
2320:                //          I suspect because it uses the local separator?
2321:                //
2322:                // Should really just get the module name from the local dir name.?
2323:                //
2324:                String localRootStr = CVSCUtilities.importPath(localRootFile
2325:                        .getPath());
2326:
2327:                int index = localRootStr.lastIndexOf('/');
2328:
2329:                // This will include the beginning slash is there is any string at all...
2330:                String repos = repositoryStr.substring(rootDirectoryStr
2331:                        .length());
2332:
2333:                if (this .deepDebug)
2334:                    CVSTracer.traceIf(true,
2335:                            "CVSProject.openProject: LOCAL ROOT CHECK\n"
2336:                                    + "   localRootStr  '" + localRootStr
2337:                                    + "'\n" + "   repos         '" + repos
2338:                                    + "'");
2339:                /*
2340:                 ** REL 5.0.7
2341:                 **
2342:                 if ( repos.length() > 0 && localRootStr.endsWith( repos ) )
2343:                 {
2344:                 localRootStr =
2345:                 localRootStr.substring
2346:                 ( 0, ( localRootStr.length() - repos.length() ) );
2347:                 }
2348:                 **
2349:                 */
2350:                if (this .deepDebug)
2351:                    CVSTracer.traceIf(true,
2352:                            "CVSProject.openProject: Establish ROOT\n"
2353:                                    + "   localRootStr  '" + localRootStr
2354:                                    + "'\n" + "   repositoryStr '"
2355:                                    + repositoryStr + "'\n"
2356:                                    + "   rootDirStr    '" + rootDirectoryStr
2357:                                    + "'\n" + "   repos         '" + repos
2358:                                    + "'");
2359:
2360:                if (repos.startsWith("/"))
2361:                    repos = repos.substring(1);
2362:                if (repos.length() < 1)
2363:                    repos = ".";
2364:
2365:                this .setRepository(repos); // This is just a "name" now...
2366:
2367:                this .setLocalRootDirectory(localRootStr);
2368:
2369:                this .setRootDirectory(rootDirectoryStr);
2370:
2371:                this .establishRootEntry(rootDirectoryStr);
2372:                /*
2373:                 ** REL5.0.6
2374:                 **
2375:                 if ( this.deepDebug )
2376:                 CVSTracer.traceIf( true,
2377:                 "CVSProject.openProject: Establish Child?\n"
2378:                 + "   repos         '" + repos + "'\n"
2379:                 + "   repositoryStr '" + repositoryStr + "'" );
2380:
2381:                 if ( repos.length() > 0 )
2382:                 {
2383:                 CVSEntry childEntry = new CVSEntry();
2384:                
2385:                 int slashIdx = repos.lastIndexOf( "/" );
2386:
2387:                 if ( slashIdx == -1 )
2388:                 childEntry.setName( repos );
2389:                 else
2390:                 childEntry.setName( repos.substring( slashIdx + 1 ) );
2391:
2392:                 childEntry.setRepository( repositoryStr );
2393:                 childEntry.setLocalDirectory( "." + repos + "/" );
2394:                 childEntry.setDirectoryEntryList( new CVSEntryVector() );
2395:
2396:                 CVSEntryVector eV = new CVSEntryVector();
2397:                 eV.appendEntry( childEntry );
2398:
2399:                 if ( this.deepDebug )
2400:                 CVSTracer.traceIf( true,
2401:                 "CVSProject.openProject: ROOT CHILD: \n"
2402:                 + childEntry.dumpString() );
2403:
2404:                 this.rootEntry.setDirectoryEntryList( eV );
2405:                 }
2406:                 **
2407:                 */
2408:                if (CVSProject.deepDebug)
2409:                    CVSTracer.traceIf(true, "CVSProject.openProject:\n"
2410:                            + "   Root Directory:  " + this .rootDirectory
2411:                            + "\n" + "   Repository:      " + this .repository
2412:                            + "\n" + "   rootRepos:       " + repositoryStr
2413:                            + "\n" + "   Local Root:      "
2414:                            + this .localRootDirectory + "\n");
2415:
2416:                if (CVSProject.deepDebug)
2417:                    CVSTracer.traceIf(true,
2418:                            "CVSProject.openProject: ROOT ENTRY\n"
2419:                                    + this .rootEntry.dumpString());
2420:
2421:                if (!readEntries()) {
2422:                    throw new IOException("ERROR reading 'Entries' file ");
2423:                }
2424:
2425:                if (CVSProject.deepDebug) {
2426:                    StringBuffer buf = new StringBuffer();
2427:
2428:                    this .dumpCVSProject(buf, "Project Open");
2429:
2430:                    CVSLog.logMsg(buf.toString());
2431:                }
2432:            }
2433:
2434:            public void removeAllEntries() {
2435:                this .rootEntry.removeAllEntries();
2436:            }
2437:
2438:            public void addNewEntry(CVSEntry entry) {
2439:                if (this .rootEntry == null) {
2440:                    CVSTracer
2441:                            .traceWithStack("CVSProject.addNewEntry: NULL ROOT ENTRY!!!!");
2442:                }
2443:
2444:                String name = entry.getName();
2445:                String localDirectory = entry.getLocalDirectory();
2446:                String repository = entry.getRepository();
2447:
2448:                this .ensureEntryHierarchy(localDirectory, repository);
2449:
2450:                CVSEntry parentEntry = (CVSEntry) this 
2451:                        .getPathTableEntry(localDirectory);
2452:
2453:                if (parentEntry == null) {
2454:                    CVSTracer.traceWithStack("ENTRY '" + entry.getFullName()
2455:                            + "' NO PARENT!");
2456:                    return;
2457:                }
2458:
2459:                parentEntry.appendEntry(entry);
2460:            }
2461:
2462:            public String reposNameToRepository(String fullRepos) {
2463:                int index = fullRepos.lastIndexOf('/');
2464:
2465:                if (index < 0) {
2466:                    CVSTracer
2467:                            .traceWithStack("CVSProject.reposNameToRepository: ERROR "
2468:                                    + "repository '"
2469:                                    + fullRepos
2470:                                    + "' has no slash!");
2471:                    return fullRepos;
2472:                } else {
2473:                    return fullRepos.substring(0, index);
2474:                }
2475:            }
2476:
2477:            public String reposNameToFileName(String fullRepos) {
2478:                int index = fullRepos.lastIndexOf('/');
2479:
2480:                if (index < 0) {
2481:                    CVSTracer
2482:                            .traceWithStack("CVSProject.reposNameToFileName: ERROR "
2483:                                    + "repository '"
2484:                                    + fullRepos
2485:                                    + "' has no slash!");
2486:                    return fullRepos;
2487:                } else {
2488:                    return fullRepos.substring(index + 1);
2489:                }
2490:            }
2491:
2492:            public boolean removeEntriesItem(CVSResponseItem item) {
2493:                CVSEntryVector entries;
2494:                boolean result = true;
2495:
2496:                if (CVSProject.deepDebug)
2497:                    CVSTracer.traceIf(true,
2498:                            "CVSProject.removeEntriesItem: pathName '"
2499:                                    + item.getPathName() + "'");
2500:
2501:                String localDirectory = this .normalizeLocalDirectory(item
2502:                        .getPathName(), this .reposNameToRepository(item
2503:                        .getRepositoryName()));
2504:
2505:                CVSEntry parentEntry = (CVSEntry) this 
2506:                        .getPathTableEntry(localDirectory);
2507:
2508:                if (parentEntry == null) {
2509:                    result = false;
2510:                    CVSTracer
2511:                            .traceWithStack("CVSProject.removeEntriesItem: NO PARENT! pathName '"
2512:                                    + item.getPathName()
2513:                                    + "' (localDir '"
2514:                                    + localDirectory + "').");
2515:                } else {
2516:                    String entryName = this .reposNameToFileName(item
2517:                            .getRepositoryName());
2518:
2519:                    result = parentEntry.removeEntry(entryName);
2520:
2521:                    //
2522:                    // MTT-delete
2523:                    // Fixes the problem in which the file is left undeleted.
2524:                    //
2525:                    if (item.getType() == CVSResponseItem.REMOVED) {
2526:                        String pathName = item.getPathName();
2527:                        if (pathName.startsWith("./"))
2528:                            pathName = pathName.substring(2);
2529:
2530:                        String fileName = this .localRootDirectory
2531:                                + File.separator + pathName + entryName;
2532:
2533:                        File file = new File(fileName.replace('/',
2534:                                File.separatorChar));
2535:                        if (!file.delete()) {
2536:                            CVSTracer
2537:                                    .traceWithStack("CVSProject.removeEntriesItem: Could not delete file "
2538:                                            + file.getAbsolutePath());
2539:                        }
2540:                    }
2541:                }
2542:
2543:                return result;
2544:            }
2545:
2546:            /**
2547:             * Given an entry, update the entry in our project. If the
2548:             * entry is new (not found), then add it to our project.
2549:             *
2550:             * @param newEntry The entry to update.
2551:             */
2552:
2553:            public void updateEntriesItem(CVSEntry newEntry) {
2554:                CVSEntry entry;
2555:                boolean result;
2556:
2557:                if (CVSProject.deepDebug)
2558:                    CVSTracer.traceIf(true,
2559:                            "CVSProject.UPDATEEntriesItem: newEntry\n"
2560:                                    + "   getFullName       '"
2561:                                    + newEntry.getFullName() + "'\n"
2562:                                    + "   getLocalDirectory '"
2563:                                    + newEntry.getLocalDirectory() + "'\n"
2564:                                    + "   getAdminEntryLine '"
2565:                                    + newEntry.getAdminEntryLine() + "'");
2566:
2567:                // REVIEW
2568:                // UNDONE
2569:                //
2570:                // When we get these from the server, typically they
2571:                // have only the first two fields filled in.
2572:                // 
2573:                // Therefore, I think it is correct to simply bother
2574:                // with the possible effects that these two first
2575:                // fields can have on our local Entries.
2576:                //
2577:                // Note: When the add command is used, it sends back
2578:                //       a 'Checked-in' with an Entry '/name/0///'.
2579:                //       CVSEntries are smart enough to recognize
2580:                //       new user files and set conflict to 'Initial...'
2581:                //       when needed.
2582:                //
2583:                //       Also, when the 'remove' command is performed,
2584:                //       it sends back a 'Checked-in' with an Entry
2585:                //       '/name/-version///'. We have to be smart enough
2586:                //       here to pickup the "marked for removal" aspect
2587:                //       only if our version match. God only knows why
2588:                //       we would ever get one that did not match our Entry... 
2589:
2590:                String name = newEntry.getName();
2591:                String localDirectory = newEntry.getLocalDirectory();
2592:
2593:                if (CVSProject.deepDebug)
2594:                    CVSTracer.traceIf(true,
2595:                            "CVSProject.updateEntriesItem: localDirectory '"
2596:                                    + localDirectory + "' name '" + name
2597:                                    + "'  ENTRY '" + newEntry + "'");
2598:
2599:                CVSEntry parentEntry = (CVSEntry) this 
2600:                        .getPathTableEntry(localDirectory);
2601:
2602:                entry = null;
2603:                if (parentEntry != null) {
2604:                    entry = parentEntry.locateEntry(name);
2605:                }
2606:
2607:                if (CVSProject.deepDebug)
2608:                    CVSTracer.traceIf(true,
2609:                            "CVSProject.updateEntriesItem: Parent '"
2610:                                    + (parentEntry == null ? "(null)"
2611:                                            : parentEntry.getFullName()) + "'");
2612:
2613:                if (entry != null) {
2614:                    // New user files are special here, since typically
2615:                    // their version string is empty (null). They can not
2616:                    // really have a conflict
2617:
2618:                    if (CVSProject.deepDebug)
2619:                        CVSTracer.traceIf(true,
2620:                                "CVSProject.updateEntriesItem: newUserfile? '"
2621:                                        + (newEntry.isNewUserFile() ? "yes"
2622:                                                : "no") + "'");
2623:
2624:                    if (!newEntry.isNewUserFile()
2625:                            && !entry.getVersion()
2626:                                    .equals(newEntry.getVersion())) {
2627:                        if (CVSProject.deepDebug)
2628:                            CVSTracer
2629:                                    .traceIf(
2630:                                            true,
2631:                                            "CVSProject.updateEntriesItem: "
2632:                                                    + "WARNING: version mismatch: Entry '"
2633:                                                    + newEntry.getFullName()
2634:                                                    + "' New '"
2635:                                                    + newEntry.getVersion()
2636:                                                    + "' Existing: '"
2637:                                                    + entry.getVersion() + "'");
2638:                    }
2639:
2640:                    // If the new entry's conflict field is not null,
2641:                    // then set the existing entry's field to the same
2642:                    // value. Since we are checking the inConflict flag
2643:                    // below, we can just deal with the string part of
2644:                    // the conflict field. The same goes for the version.
2645:
2646:                    if (newEntry.getVersion() != null)
2647:                        entry.setVersion(newEntry.getVersion());
2648:
2649:                    if (newEntry.isNewUserFile())
2650:                        entry.setNewUserFile(true);
2651:
2652:                    if (newEntry.isToBeRemoved())
2653:                        entry.setToBeRemoved(true);
2654:
2655:                    // completeTimestamp() returns the 'timestamp+conflict' format,
2656:                    // which setTimestamp() will properly parse for conflict info.
2657:                    if (newEntry.completeTimestamp() != null)
2658:                        entry.setTimestamp(newEntry.completeTimestamp());
2659:
2660:                    if (newEntry.getOptions() != null
2661:                            && newEntry.getOptions().length() > 0)
2662:                        entry.setOptions(newEntry.getOptions());
2663:
2664:                    if (newEntry.getTag() != null) {
2665:                        entry.setTag(newEntry.getTag());
2666:                    } else if (newEntry.getDate() != null) {
2667:                        entry.setDate(newEntry.getDate());
2668:                    } else {
2669:                        // This one call nulls both tag and date.
2670:                        entry.setTag(null);
2671:                    }
2672:
2673:                    entry.setDirty(true);
2674:
2675:                    if (CVSProject.deepDebug)
2676:                        CVSTracer.traceIf(true,
2677:                                "CVSProject.updateEntriesItem: FINAL:\n"
2678:                                        + "   getFullName       '"
2679:                                        + entry.getFullName() + "'\n"
2680:                                        + "   getAdminEntryLine '"
2681:                                        + entry.getAdminEntryLine() + "'\n"
2682:                                        + "   getLocalDirectory '"
2683:                                        + entry.getLocalDirectory() + "'");
2684:                } else {
2685:                    if (parentEntry == null) {
2686:                        CVSTracer
2687:                                .traceIf(true,
2688:                                        "CVSProject.updateEntriesItem: PARENT IS NULL!!!");
2689:                        CVSTracer.traceWithStack("NULL PARENT!");
2690:                    }
2691:                    this .addNewEntry(newEntry);
2692:                    newEntry.setDirty(true);
2693:                }
2694:            }
2695:
2696:            // REVIEW
2697:            // This method should be throwing exceptions! not returning false.
2698:
2699:            public boolean readEntries() {
2700:                boolean ok = true;
2701:
2702:                if (CVSProject.debugEntryIO)
2703:                    CVSTracer.traceIf(true, "CVSProject.readEntries:\n"
2704:                            + "   locaRootPath '" + this .getLocalRootPath()
2705:                            + "'\n" + "   ROOT ENTRY   '"
2706:                            + this .rootEntry.dumpString() + "'");
2707:
2708:                String rootStr = CVSCUtilities.exportPath(this 
2709:                        .getLocalRootPath());
2710:
2711:                File workingDirectory = new File(rootStr);
2712:
2713:                if (CVSProject.debugEntryIO)
2714:                    CVSTracer.traceIf(true, "CVSProject.readEntries:\n"
2715:                            + "   WkgDirPath '" + workingDirectory.getPath()
2716:                            + "'");
2717:
2718:                CVSEntryVector entries = this .readEntriesFile(this .rootEntry,
2719:                        workingDirectory);
2720:
2721:                if (entries != null)
2722:                    this .rootEntry.setDirectoryEntryList(entries);
2723:                else
2724:                    return false;
2725:
2726:                return true;
2727:            }
2728:
2729:            /**
2730:             * @param dirEntry The entry of the directory being loaded.
2731:             * @param workingDirectory The local file system directory of dirEntry.
2732:             */
2733:
2734:            public CVSEntryVector readEntriesFile(CVSEntry dirEntry,
2735:                    File workingDirectory) {
2736:                int linenum = 0;
2737:                String line = null;
2738:                boolean ok = true;
2739:                boolean isDir = false;
2740:                BufferedReader in = null;
2741:
2742:                CVSEntryVector entries = new CVSEntryVector();
2743:
2744:                // Compute the 'local directory' that this Entry will exchange
2745:                // with the server during the protocol...
2746:
2747:                String localDirectory = CVSCUtilities
2748:                        .importPath(workingDirectory.getPath().substring(
2749:                                this .localRootDirectory.length()));
2750:
2751:                if (localDirectory.startsWith("/"))
2752:                    localDirectory = localDirectory.substring(1);
2753:
2754:                localDirectory = CVSCUtilities.ensureFinalSlash("./"
2755:                        + localDirectory);
2756:
2757:                if (CVSProject.debugEntryIO)
2758:                    CVSTracer.traceIf(true,
2759:                            "CVSProject.readEntriesFile: ENTER\n"
2760:                                    + "   wkgDir    '"
2761:                                    + workingDirectory.getPath() + "'\n"
2762:                                    + "   localDir  '" + localDirectory + "'\n"
2763:                                    + "   dirEntry\n"
2764:                                    + dirEntry.dumpString("   "));
2765:
2766:                // ===============  ROOT  ======================
2767:                String adminRootPath = CVSProject
2768:                        .rootPathToAdminPath(CVSCUtilities
2769:                                .importPath(workingDirectory.getPath()));
2770:
2771:                File adminRootFile = new File(CVSCUtilities
2772:                        .exportPath(CVSProject.getAdminRootPath(adminRootPath)));
2773:
2774:                if (CVSProject.debugEntryIO)
2775:                    CVSTracer.traceIf(true,
2776:                            "CVSProject.readEntriesFile: adminRootFile '"
2777:                                    + adminRootFile.getPath() + "'\n");
2778:
2779:                String rootDirectoryStr = this .readRootDirectory(adminRootFile);
2780:
2781:                if (rootDirectoryStr == null) {
2782:                    CVSLog.logMsg("ERROR admin 'Root' file '"
2783:                            + adminRootFile.getPath() + "' is empty!");
2784:                    return null;
2785:                }
2786:
2787:                //
2788:                // We had to modify this code to accomodate Win32 servers.
2789:                // They have root directories such as 'C:\projects\cvs'.
2790:                // Thus, you end up with cvs specifications such as this:
2791:                //       :pserver:user@host.domain:C:/src/cvs
2792:                //
2793:                // In that case, the following commented line of code would
2794:                // incorrectly use the path *after* the drive letter + colon,
2795:                // which of course if not correct and hoses the server and
2796:                // all of our root prefix checks!
2797:                //
2798:                // To fix the code, we change the code to count three colons
2799:                // to the right from the left, as opposed to the old code
2800:                // which counted one left from the right.
2801:                //
2802:                // Thanks to Manfred Usselmann <Usselmann.M@icg-online.de>
2803:                // for solving this and providing the patch.
2804:                //
2805:                // int index = rootDirectoryStr.lastIndexOf( ':' );
2806:                //
2807:                // REVIEW This patch was submitted, but I do not understand
2808:                //        in what context it ever occurs to be fixed. TGE
2809:                // GG-NT-no-server  Gérard COLLIN <gcollin@netonomy.com>
2810:                //    Changed to searching first : after @ because of
2811:                //    "user@host.domain:C:/src/cvs" specifications
2812:                //
2813:                //	int index = -1;
2814:                //	index = rootDirectoryStr.indexOf( '@');
2815:                //	if ( index >= 0 )
2816:                //		{
2817:                //		index = rootDirectoryStr.indexOf( ':', index+1 );
2818:                //		if ( index >= 0 )
2819:                //			{
2820:                //			rootDirectoryStr =
2821:                //			rootDirectoryStr.substring( index + 1 );
2822:                //			}
2823:                //		}
2824:                //
2825:
2826:                int index = -1;
2827:
2828:                if (!rootDirectoryStr.startsWith(":")) {
2829:                    // "user@host.domain:C:/src/cvs"
2830:                    index = rootDirectoryStr.indexOf(':', 0);
2831:                } else {
2832:                    for (int i = 0; i < 3; ++i) {
2833:                        index = rootDirectoryStr.indexOf(':', index + 1);
2834:                        if (index == -1)
2835:                            break;
2836:                    }
2837:                }
2838:
2839:                if (index >= 0) {
2840:                    rootDirectoryStr = rootDirectoryStr.substring(index + 1);
2841:                } else {
2842:                    CVSLog.logMsg("ERROR admin 'Root' file is MISSING COLONS!");
2843:                }
2844:
2845:                // ============  REPOSITORY  ===================
2846:                File adminRepositoryFile = new File(CVSCUtilities
2847:                        .exportPath(CVSProject
2848:                                .getAdminRepositoryPath(adminRootPath)));
2849:
2850:                if (CVSProject.debugEntryIO)
2851:                    CVSTracer.traceIf(true,
2852:                            "CVSProject.readEntriesFile: adminRepositoryFile '"
2853:                                    + adminRepositoryFile.getPath() + "'\n");
2854:
2855:                String repositoryStr = this .readRepository(adminRepositoryFile);
2856:                if (repositoryStr == null) {
2857:                    CVSLog.logMsg("ERROR admin 'Repository' file '"
2858:                            + adminRepositoryFile.getPath() + "' is empty!");
2859:                    return null;
2860:                }
2861:
2862:                // NOTE
2863:                // It appears that when the CVS command line checks out a
2864:                // working directory, it sometimes (some versions?) sets the
2865:                // repository to a path *relative* to the root directory.
2866:                // Since jCVS expects a full pathname, we normalize here.
2867:                //
2868:                // Thanks to Thorsten Ludewig <Thorsten.Ludewig@FH-Wolfenbuettel.DE>
2869:                // for sending the patch for this.
2870:                //
2871:                if (!repositoryStr.startsWith(rootDirectoryStr)) {
2872:                    // GG-dot-rep . repositoryStr should be ignored.
2873:                    if (repositoryStr.equals("."))
2874:                        repositoryStr = rootDirectoryStr;
2875:                    else
2876:                        repositoryStr = rootDirectoryStr + "/" + repositoryStr;
2877:                }
2878:
2879:                // ============  TABLE ENTRY  ===================
2880:                dirEntry.setRepository(repositoryStr);
2881:                this .pathTable.put(localDirectory, dirEntry);
2882:
2883:                if (CVSProject.debugEntryIO)
2884:                    CVSTracer.traceIf(true,
2885:                            "READENTRIES: ADDED PATH TABLE ENTRY\n"
2886:                                    + "   dirEntry:       "
2887:                                    + dirEntry.getFullName() + "\n"
2888:                                    + "   localDirectory: " + localDirectory
2889:                                    + "\n" + "   repository:     "
2890:                                    + repositoryStr);
2891:
2892:                // ==============  ENTRIES  ===================
2893:
2894:                // First, make sure we pick up and process Entries.Log
2895:                //
2896:                try {
2897:                    CVSCUtilities.integrateEntriesLog(new File(CVSCUtilities
2898:                            .exportPath(adminRootPath)));
2899:                } catch (IOException ex) {
2900:                    CVSLog
2901:                            .logMsg("ERROR integrating 'Entries.Log' file in Admin Path '"
2902:                                    + adminRootPath + "', " + ex.getMessage());
2903:                    ex.printStackTrace();
2904:                }
2905:
2906:                File entriesFile = new File(CVSCUtilities.exportPath(CVSProject
2907:                        .getAdminEntriesPath(adminRootPath)));
2908:
2909:                if (CVSProject.debugEntryIO)
2910:                    CVSTracer.traceIf(true,
2911:                            "CVSProject.readEntriesFile: entriesFile '"
2912:                                    + entriesFile.getPath() + "'\n");
2913:
2914:                try {
2915:                    in = new BufferedReader(new FileReader(entriesFile));
2916:                } catch (IOException ex) {
2917:                    in = null;
2918:                    ok = false;
2919:                }
2920:
2921:                for (linenum = 1; ok; ++linenum) {
2922:                    try {
2923:                        line = in.readLine();
2924:                    } catch (IOException ex) {
2925:                        line = null;
2926:                        break;
2927:                    }
2928:
2929:                    if (line == null)
2930:                        break;
2931:
2932:                    // UNDONE
2933:                    // We need to properly handle "D/" entries (i.e. look up subfolders
2934:                    // that contain CVS admin directories).
2935:                    //
2936:                    // Lines that starts with "D" are directories!
2937:                    if (line.startsWith("D")) {
2938:                        isDir = true;
2939:                        line = line.substring(1);
2940:                    }
2941:
2942:                    if (line.startsWith("/")) {
2943:                        CVSEntry entry = new CVSEntry();
2944:
2945:                        try {
2946:                            entry.parseEntryLine(line, false);
2947:                        } catch (ParseException ex) {
2948:                            // UNDONE
2949:                            CVSLog.logMsg("Bad admin 'Entries' line " + linenum
2950:                                    + ", '" + line + "' isDir '" + isDir
2951:                                    + "' - " + ex.getMessage());
2952:                            ok = false;
2953:                        }
2954:
2955:                        if (ok) {
2956:                            if (CVSProject.debugEntryIO)
2957:                                CVSTracer.traceIf(true,
2958:                                        "CVSProject.readEntriesFile: PARSED ENTRY\n"
2959:                                                + "   entry:          "
2960:                                                + entry.getName() + "\n"
2961:                                                + "   repository:     "
2962:                                                + repositoryStr + "\n"
2963:                                                + "   localDirectory: "
2964:                                                + localDirectory);
2965:
2966:                            entry.setRepository(repositoryStr);
2967:                            entry.setLocalDirectory(localDirectory);
2968:
2969:                            entries.appendEntry(entry);
2970:
2971:                            if (isDir) {
2972:                                String newLocal = localDirectory
2973:                                        + entry.getName() + "/";
2974:
2975:                                String newRepos = repositoryStr + "/"
2976:                                        + entry.getName();
2977:
2978:                                entry.setRepository(newRepos);
2979:                                entry.setLocalDirectory(newLocal);
2980:
2981:                                String newWkgPath = workingDirectory.getPath()
2982:                                        + File.separator + entry.getName()
2983:                                        + File.separator;
2984:
2985:                                String adminPath = newLocal + "CVS";
2986:
2987:                                File newWorking = new File(workingDirectory,
2988:                                        entry.getName());
2989:                                //	this.localRootDirectory + "/"
2990:                                //	+ localDirectory + entry.getName()
2991:                                //	);
2992:
2993:                                if (CVSProject.debugEntryIO)
2994:                                    CVSTracer.traceIf(true,
2995:                                            "readEntriesFile: IS DIRECTORY:\n"
2996:                                                    + "   entriesFile   '"
2997:                                                    + entriesFile.getPath()
2998:                                                    + "'\n"
2999:                                                    + "   NewWorkingDir '"
3000:                                                    + newWorking.getPath()
3001:                                                    + "'\n"
3002:                                                    + "   newRepos      '"
3003:                                                    + newRepos + "'\n"
3004:                                                    + "   newLocal      '"
3005:                                                    + newLocal + "'");
3006:
3007:                                CVSEntryVector newEntries = readEntriesFile(
3008:                                        entry, newWorking);
3009:
3010:                                if (newEntries == null) {
3011:                                    CVSLog
3012:                                            .logMsg("ERROR failed reading Entries file from '"
3013:                                                    + newWorking.getPath()
3014:                                                    + "'");
3015:
3016:                                    newEntries = new CVSEntryVector();
3017:                                }
3018:
3019:                                entry.setDirectoryEntryList(newEntries);
3020:                            }
3021:                        }
3022:
3023:                        isDir = false; // reset the directory flag.
3024:                    }
3025:                }
3026:
3027:                if (in != null) {
3028:                    try {
3029:                        in.close();
3030:                    } catch (IOException ex) {
3031:                    }
3032:                }
3033:
3034:                return entries;
3035:            }
3036:
3037:            public boolean writeAdminFiles() {
3038:                boolean result = false;
3039:
3040:                String localPath = this .getLocalRootDirectory();
3041:
3042:                if (CVSProject.debugEntryIO)
3043:                    CVSTracer.traceIf(true,
3044:                            "CVSProject.writeAdminFiles: WRITE ADMIN FILES\n"
3045:                                    + "   localPath   '" + localPath + "'\n"
3046:                                    + "   rootEntry    "
3047:                                    + this .rootEntry.dumpString());
3048:
3049:                result = this .writeAdminAndDescend(localPath, this .rootEntry);
3050:
3051:                if (!result) {
3052:                    // UNDONE - can we report better here?
3053:                    CVSLog
3054:                            .logMsg("CVSProject.writeAdminFiles:\n"
3055:                                    + "  ERROR Writing the CVS administrative files FAILED!");
3056:                }
3057:
3058:                return result;
3059:            }
3060:
3061:            private boolean writeAdminAndDescend(String localRoot,
3062:                    CVSEntry dirEntry) {
3063:                int i;
3064:                boolean result = true;
3065:
3066:                String localDir = dirEntry.getLocalDirectory();
3067:
3068:                String localPath = localRoot;
3069:                if (localDir.length() > 2) {
3070:                    localPath = localPath + "/" + localDir.substring(2);
3071:                }
3072:
3073:                if (CVSProject.debugEntryIO)
3074:                    CVSTracer.traceIf(true,
3075:                            "CVSProject.writeAdminFiles: WRITE AND DESCEND LOCAL PATH\n"
3076:                                    + "   localPath   '" + localPath + "'");
3077:
3078:                String adminRootPath = CVSProject
3079:                        .rootPathToAdminPath(localPath);
3080:
3081:                File adminFile = new File(CVSCUtilities
3082:                        .exportPath(adminRootPath));
3083:
3084:                File rootFile = new File(CVSCUtilities.exportPath(CVSProject
3085:                        .getAdminRootPath(adminRootPath)));
3086:
3087:                File reposFile = new File(CVSCUtilities.exportPath(CVSProject
3088:                        .getAdminRepositoryPath(adminRootPath)));
3089:
3090:                File entriesFile = new File(CVSCUtilities.exportPath(CVSProject
3091:                        .getAdminEntriesPath(adminRootPath)));
3092:
3093:                CVSEntryVector entries = dirEntry.getEntryList();
3094:
3095:                if (CVSProject.debugEntryIO) {
3096:                    CVSTracer.traceIf(true,
3097:                            "===================================="
3098:                                    + "====================================");
3099:                    CVSTracer.traceIf(true,
3100:                            "CVSProject.writeAdminAndDescend:\n"
3101:                                    + "   dirEntry      '"
3102:                                    + dirEntry.getFullName()
3103:                                    + "'\n"
3104:                                    + "   isDirty       '"
3105:                                    + dirEntry.isDirty()
3106:                                    + "'\n"
3107:                                    + "   dirRepos      '"
3108:                                    + dirEntry.getRepository()
3109:                                    + "'\n"
3110:                                    + "   localRoot     '"
3111:                                    + localPath
3112:                                    + "'\n"
3113:                                    + "   localDir      '"
3114:                                    + localDir
3115:                                    + "'\n"
3116:                                    + "   adminFile     '"
3117:                                    + adminFile.getPath()
3118:                                    + "'\n"
3119:                                    + "   rootFile      '"
3120:                                    + rootFile.getPath()
3121:                                    + "'\n"
3122:                                    + "   reposFile     '"
3123:                                    + reposFile.getPath()
3124:                                    + "'\n"
3125:                                    + "   entriesFile   '"
3126:                                    + entriesFile.getPath()
3127:                                    + "'\n"
3128:                                    + "   entries.size  '"
3129:                                    + entries.size()
3130:                                    + "'\n"
3131:                                    + "   entries.dirty '"
3132:                                    + entries.isDirty() + "'");
3133:                }
3134:
3135:                if (!dirEntry.isDirty() && !entries.isDirty()) {
3136:                    if (CVSProject.debugEntryIO)
3137:                        CVSTracer.traceIf(true,
3138:                                "\nCVSProject.writeAdminAndDescend: "
3139:                                        + "NO DIRTY ENTRIES --> SKIP WRITE\n");
3140:                } else {
3141:                    if (!adminFile.exists()) {
3142:                        if (!adminFile.mkdir()) {
3143:                            CVSTracer
3144:                                    .traceWithStack("ERROR could not create the admin directory '"
3145:                                            + adminFile.getPath() + "'");
3146:                        }
3147:                    }
3148:
3149:                    // ==============    ENTRIES   ==================
3150:                    result = this .writeAdminEntriesFile(entriesFile, entries);
3151:
3152:                    if (result) {
3153:                        // ==============    ROOT   ==================
3154:                        String rootDirStr = this .projectDef
3155:                                .getRootDirectorySpec();
3156:
3157:                        if (CVSProject.debugEntryIO)
3158:                            CVSTracer.traceIf(true,
3159:                                    "CVSProject.writeAdminAndDescend: WRITE ROOT FILE\n"
3160:                                            + "   rootFile   '"
3161:                                            + rootFile.getPath() + "'\n"
3162:                                            + "   " + rootDirStr);
3163:
3164:                        result = this .writeAdminRootFile(rootFile, rootDirStr);
3165:
3166:                        // ==============    REPOSITORY   ==================
3167:                        if (result) {
3168:                            if (CVSProject.debugEntryIO)
3169:                                CVSTracer.traceIf(true,
3170:                                        "CVSProject.writeAdminAndDescend: WRITE REPOSITORYy FILE\n"
3171:                                                + "   reposFile  '"
3172:                                                + reposFile.getPath() + "'\n"
3173:                                                + "   "
3174:                                                + dirEntry.getRepository());
3175:
3176:                            result = this .writeAdminRepositoryFile(reposFile,
3177:                                    dirEntry.getRepository());
3178:                        }
3179:                    }
3180:                }
3181:
3182:                if (!result) {
3183:                    CVSLog.logMsg("CVSProject.writeAdminAndDescend: "
3184:                            + "ERROR writing admin files '"
3185:                            + entriesFile.getPath() + "' et.al.");
3186:                    result = false;
3187:                }
3188:
3189:                for (i = 0; result && i < entries.size(); ++i) {
3190:                    CVSTracer.traceIf(CVSProject.debugEntryIO,
3191:                            "CVSProject.writeAdminAndDescend: LOOP i = " + i);
3192:
3193:                    CVSEntry entry = entries.entryAt(i);
3194:
3195:                    CVSTracer.traceIf(CVSProject.debugEntryIO,
3196:                            "CVSProject.writeAdminAndDescend: " + "LOOP[" + i
3197:                                    + "] repository '" + repository
3198:                                    + "' entry '" + entry.getName() + "'");
3199:
3200:                    if (entry.isDirectory()) {
3201:                        // REVIEW I know this is gonna fail on subtrees!!!
3202:                        //
3203:                        CVSTracer.traceIf(CVSProject.debugEntryIO,
3204:                                "CVSProject.writeAdminAndDescend: "
3205:                                        + "DESCEND into '"
3206:                                        + entry.getFullName() + "'");
3207:
3208:                        result = this .writeAdminAndDescend(localRoot, entry);
3209:
3210:                        CVSTracer.traceIf(CVSProject.debugEntryIO,
3211:                                "CVSProject.writeAdminAndDescend: "
3212:                                        + "RETURNED from '"
3213:                                        + entry.getFullName() + "' with '"
3214:                                        + result + "'");
3215:                    }
3216:                }
3217:
3218:                if (result) {
3219:                    entries.setDirty(false);
3220:                    dirEntry.setDirty(false);
3221:                }
3222:
3223:                CVSTracer
3224:                        .traceIf(CVSProject.debugEntryIO,
3225:                                "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3226:                return result;
3227:            }
3228:
3229:            public boolean writeAdminEntriesFile(File entriesFile,
3230:                    CVSEntryVector entries) {
3231:                boolean ok = true;
3232:                boolean result = true;
3233:                CVSEntry entry = null;
3234:                BufferedWriter out = null;
3235:
3236:                try {
3237:                    out = new BufferedWriter(new FileWriter(entriesFile));
3238:                } catch (Exception ex) {
3239:                    CVSLog.logMsg("CVSProject.writeAdminEntriesFile: "
3240:                            + "ERROR opening entries file '"
3241:                            + entriesFile.getPath() + "' - " + ex.getMessage());
3242:
3243:                    return false;
3244:                }
3245:
3246:                for (int i = 0; result && i < entries.size(); ++i) {
3247:                    entry = entries.entryAt(i);
3248:
3249:                    try {
3250:                        out.write(entry.getAdminEntryLine());
3251:                        out.newLine();
3252:                    } catch (IOException ex) {
3253:                        CVSLog.logMsg("CVSProject.writeAdminEntriesFile: "
3254:                                + "ERROR writing entries file '"
3255:                                + entriesFile.getPath() + "' - "
3256:                                + ex.getMessage());
3257:
3258:                        result = false;
3259:                    }
3260:                }
3261:
3262:                try {
3263:                    out.close();
3264:                } catch (IOException ex) {
3265:                    CVSLog.logMsg("CVSProject.writeAdminEntriesFile: "
3266:                            + "ERROR closing entries file '"
3267:                            + entriesFile.getPath() + "' - " + ex.getMessage());
3268:
3269:                    result = false;
3270:                }
3271:
3272:                return result;
3273:            }
3274:
3275:            public boolean writeAdminRootFile(File rootFile,
3276:                    String rootDirectoryStr) {
3277:                boolean result = true;
3278:                BufferedWriter out = null;
3279:
3280:                try {
3281:                    out = new BufferedWriter(new FileWriter(rootFile));
3282:                } catch (Exception ex) {
3283:                    CVSLog.logMsg("CVSProject.writeAdminRootFile: "
3284:                            + "failed opening 'Root' file to '"
3285:                            + rootFile.getPath() + "' - " + ex.getMessage());
3286:                    result = false;
3287:                }
3288:
3289:                if (result) {
3290:                    try {
3291:                        out.write(rootDirectoryStr);
3292:                        out.newLine();
3293:                        out.close();
3294:                    } catch (IOException ex) {
3295:                        CVSLog
3296:                                .logMsg("CVSProject.writeAdminRootFile: "
3297:                                        + "failed writing 'Root' file to '"
3298:                                        + rootFile.getPath() + "' - "
3299:                                        + ex.getMessage());
3300:                        result = false;
3301:                    }
3302:                }
3303:
3304:                return result;
3305:            }
3306:
3307:            public boolean writeAdminRepositoryFile(File repFile,
3308:                    String repository) {
3309:                boolean result = true;
3310:                BufferedWriter out = null;
3311:
3312:                if (CVSProject.deepDebug)
3313:                    CVSTracer.traceIf(true,
3314:                            "CVSProject.writeAdminRepositoryFile:\n"
3315:                                    + "   File:   " + repFile.getPath() + "\n"
3316:                                    + "   Repos:  " + repository);
3317:
3318:                try {
3319:                    out = new BufferedWriter(new FileWriter(repFile));
3320:                } catch (Exception ex) {
3321:                    CVSLog.logMsg("CVSProject.writeAdminRepositoryFile: "
3322:                            + "failed opening 'Repository' file to '"
3323:                            + repFile.getPath() + "' - " + ex.getMessage());
3324:                    result = false;
3325:                }
3326:
3327:                if (result) {
3328:                    try {
3329:                        out.write(repository);
3330:                        out.newLine();
3331:                        out.close();
3332:                    } catch (IOException ex) {
3333:                        CVSLog.logMsg("CVSProject.writeAdminRepositoryFile: "
3334:                                + "failed writing 'Repository' file to '"
3335:                                + repFile.getPath() + "' - " + ex.getMessage());
3336:                        result = false;
3337:                    }
3338:                }
3339:
3340:                return result;
3341:            }
3342:
3343:            public boolean isLocalFileModified(CVSEntry entry) {
3344:                File entryFile = this .getEntryFile(entry);
3345:                return entry.isLocalFileModified(entryFile);
3346:            }
3347:
3348:            /**
3349:             * This is used for the 'release' command to determine
3350:             * if the project has any modifications the user might
3351:             * not want to lose.
3352:             *
3353:             * @return True if the project has any changes user might want to save.
3354:             */
3355:
3356:            public boolean checkReleaseStatus(CVSIgnore ignore, Vector mods,
3357:                    Vector adds, Vector rems, Vector unks) {
3358:                //
3359:                // NOTE
3360:                // WARNING !!!
3361:                // 
3362:                // THESE METHODS that operate on the localRootDirectory
3363:                // MUST BE VERY CAREFUL!
3364:                //
3365:                // The problem is that the root entry of the project always
3366:                // point to the very root of the project, even if the user
3367:                // "sees" some subtree of the repository in question. When
3368:                // the user is looking at a subtree, and they do a "release",
3369:                // they do not expect the top level to be removed!!!!!!!!
3370:                // They expect the "root level entries" to be released!
3371:                //
3372:                // Ergo, we must compute the local root directory for the
3373:                // release based on both the localRootDirectory and the
3374:                // local directory of one of the root level entries.
3375:                //
3376:                CVSEntryVector rootEntries = this .getRootEntry().getEntryList();
3377:                if (rootEntries == null || rootEntries.size() == 0) {
3378:                    CVSTracer.traceWithStack("THIS SHOULD NEVER HAPPEN!!");
3379:                    return true;
3380:                }
3381:
3382:                this .checkReleaseAndDescend(this .getRootEntry(), ignore, mods,
3383:                        adds, rems, unks);
3384:
3385:                return (mods.size() > 0 || adds.size() > 0 || rems.size() > 0 || unks
3386:                        .size() > 0);
3387:            }
3388:
3389:            private void checkReleaseAndDescend(CVSEntry parent,
3390:                    CVSIgnore ignore, Vector mods, Vector adds, Vector rems,
3391:                    Vector unks) {
3392:                CVSEntryVector entries = parent.getEntryList();
3393:
3394:                File dirF = this .getLocalEntryFile(parent);
3395:                String[] list = dirF.list();
3396:                Vector fileV = new Vector((list == null) ? 0 : list.length);
3397:
3398:                if (list != null) {
3399:                    for (int i = 0; i < list.length; ++i)
3400:                        fileV.addElement(list[i]);
3401:                }
3402:
3403:                for (int i = 0; i < entries.size(); ++i) {
3404:                    CVSEntry entry = entries.entryAt(i);
3405:
3406:                    // Anything we have an entry for is not unknown
3407:                    fileV.removeElement(entry.getName());
3408:
3409:                    if (entry.isDirectory()) {
3410:                        this .checkReleaseAndDescend(entry, ignore, mods, adds,
3411:                                rems, unks);
3412:                    } else {
3413:                        if (entry.isNewUserFile())
3414:                            adds.addElement(entry.getFullName());
3415:                        else if (entry.isToBeRemoved())
3416:                            rems.addElement(entry.getFullName());
3417:                        else if (entry.isInConflict())
3418:                            mods.addElement(entry.getFullName());
3419:                        else if (this .isLocalFileModified(entry))
3420:                            mods.addElement(entry.getFullName());
3421:                        else if (this .isLocalFileModified(entry))
3422:                            mods.addElement(entry.getFullName());
3423:                    }
3424:                }
3425:
3426:                for (int i = 0, sz = fileV.size(); i < sz; ++i) {
3427:                    String fileName = (String) fileV.elementAt(i);
3428:                    if (!ignore.isFileToBeIgnored(fileName)) {
3429:                        // parent is a dir entry, which always has a '/'
3430:                        // on the end of its fullname.
3431:                        unks.addElement(parent.getFullName() + fileName);
3432:                    }
3433:                }
3434:            }
3435:
3436:            public void pruneEmptySubDirs(boolean saveAdminFiles) {
3437:                this .pruneEmptySubDirs(this .getRootEntry());
3438:
3439:                if (saveAdminFiles) {
3440:                    this .writeAdminFiles();
3441:                }
3442:            }
3443:
3444:            public void pruneEmptySubDirs(CVSEntry parent) {
3445:                CVSEntryVector entries = parent.getEntryList();
3446:                for (int i = entries.size() - 1; i >= 0; --i) {
3447:                    CVSEntry entry = entries.getEntryAt(i);
3448:                    if (entry.isDirectory()) {
3449:                        File dirF = this .getEntryFile(entry);
3450:                        String[] list = dirF.list();
3451:                        // MTT-null-list
3452:                        if (list == null || list.length == 0) {
3453:                            this .descendAndDelete(dirF);
3454:                            parent.removeEntry(entry);
3455:                        } else if (list.length == 1 && list[0].equals("CVS")) {
3456:                            File cvsF = new File(dirF, "CVS");
3457:                            if ((!cvsF.exists()) || cvsF.isDirectory()) {
3458:                                this .descendAndDelete(dirF);
3459:                                parent.removeEntry(entry);
3460:                            }
3461:                        } else {
3462:                            this .pruneEmptySubDirs(entry);
3463:                        }
3464:                    }
3465:                }
3466:            }
3467:
3468:            public void releaseProject() {
3469:                //
3470:                // NOTE
3471:                // WARNING !!!
3472:                // 
3473:                // THESE METHODS that operate on the localRootDirectory
3474:                // MUST BE VERY CAREFUL!
3475:                //
3476:                // The problem is that the root entry of the project always
3477:                // point to the very root of the project, even if the user
3478:                // "sees" some subtree of the repository in question. When
3479:                // the user is looking at a subtree, and they do a "release",
3480:                // they do not expect the top level to be removed!!!!!!!!
3481:                // They expect the "root level entries" to be released!
3482:                //
3483:                // Ergo, we must compute the local root directory for the
3484:                // release based on both the localRootDirectory and the
3485:                // local directory of one of the root level entries.
3486:                //
3487:                CVSEntryVector rootEntries = this .getRootEntry().getEntryList();
3488:                if (rootEntries == null || rootEntries.size() == 0) {
3489:                    CVSTracer.traceWithStack("THIS SHOULD NEVER HAPPEN!!");
3490:                    return;
3491:                }
3492:
3493:                for (int i = rootEntries.size() - 1; i >= 0; --i) {
3494:                    CVSEntry entry = rootEntries.getEntryAt(i);
3495:
3496:                    File eFile = this .getEntryFile(entry);
3497:
3498:                    //
3499:                    // SANITY CHECK
3500:                    // To at least make CERTAIN that we never delete anythig
3501:                    // above the localRootDirectory...
3502:                    //
3503:
3504:                    if (!CVSCUtilities.isSubpathInPath(this .getLocalRootPath(),
3505:                            eFile.getPath())) {
3506:                        String msg = "ROOT '" + this .getLocalRootPath()
3507:                                + "' NOT parent of '" + eFile.getPath() + "'";
3508:                        CVSTracer.traceWithStack(msg);
3509:                        return;
3510:                    }
3511:
3512:                    this .descendAndDelete(eFile);
3513:                }
3514:
3515:                // UNDONE We need to adjust the "top level Entries" here...
3516:
3517:                File rootDir = new File(this .getLocalRootDirectory());
3518:                if (rootDir.exists()) {
3519:                    String[] files = rootDir.list();
3520:                    if (files == null || files.length < 2) {
3521:                        // NOTE
3522:                        // This is very important! As long as we have
3523:                        // the top level CVS admin directory, it is critical
3524:                        // that we only delete it if it is the ONLY file 
3525:                        // left at the top level!
3526:                        //
3527:                        // UNTIL, that is, we fix the above UNDONE wrt Entries.
3528:                        //
3529:                        boolean doit = true;
3530:                        if (files.length == 1) {
3531:                            if (files[0].equals("CVS")) {
3532:                                File cvsDir = new File(rootDir, "CVS");
3533:
3534:                                files = cvsDir.list();
3535:                                for (int c = 0; c < files.length; ++c) {
3536:                                    File dFile = new File(cvsDir, files[c]);
3537:                                    dFile.delete();
3538:                                }
3539:
3540:                                cvsDir.delete();
3541:                            } else {
3542:                                doit = false;
3543:                            }
3544:                        }
3545:
3546:                        if (doit) {
3547:                            rootDir.delete();
3548:                        }
3549:                    }
3550:                }
3551:            }
3552:
3553:            private void descendAndDelete(File eFile) {
3554:                if (eFile.isDirectory()) {
3555:                    String[] files = eFile.list();
3556:
3557:                    if (files != null) {
3558:                        for (int i = 0; i < files.length; ++i) {
3559:                            File f = new File(eFile, files[i]);
3560:                            if (f.exists()) {
3561:                                this .descendAndDelete(f);
3562:                            }
3563:                        }
3564:                    }
3565:                }
3566:
3567:                eFile.delete();
3568:            }
3569:
3570:            // 
3571:            // This is tricky.
3572:            // We have to go back to the project's entries list
3573:            // to make the check, since the entry sent from the
3574:            // server will not reflect the local timestamp!
3575:            //
3576:            public boolean checkOverwrite(CVSEntry entry, File file) {
3577:                // UNDONE
3578:                // The current algorithm is very weak.
3579:                boolean result = true;
3580:
3581:                if (CVSProject.deepDebug)
3582:                    CVSTracer.traceIf(true, "CVSProject.checkOverWrite( "
3583:                            + entry.getFullName() + ", " + file.getPath()
3584:                            + " )");
3585:
3586:                if (!file.exists()) {
3587:                    // Does not exist, no problem overwriting...
3588:                    CVSTracer.trace("CVSProject.checkOverWrite: FILE '"
3589:                            + file.getPath() + "' DOES NOT EXIST");
3590:                    return true;
3591:                }
3592:
3593:                CVSEntry checkEntry = this .locateEntry(entry.getFullName());
3594:
3595:                if (checkEntry == null) {
3596:                    NullPointerException ex = new NullPointerException(
3597:                            "locateEntry(" + entry.getFullName()
3598:                                    + ") returns null!");
3599:                    CVSLog.traceMsg(ex, "CVSProject.checkOverWrite:");
3600:                    return false;
3601:                }
3602:
3603:                // Check the timstamps...
3604:                result = !checkEntry.isLocalFileModified(file);
3605:
3606:                CVSTracer.traceIf(false, "CVSProject.checkOverWrite: RESULT '"
3607:                        + result + "'");
3608:
3609:                return result;
3610:            }
3611:
3612:            public CVSEntry locateEntry(String fullPath) {
3613:                CVSEntry entry = null;
3614:
3615:                if (CVSProject.deepDebug)
3616:                    CVSTracer.traceIf(true, "CVSProject.locateEntry( "
3617:                            + fullPath + " )");
3618:
3619:                int index = fullPath.lastIndexOf('/');
3620:                if (index < 0) {
3621:                    CVSTracer
3622:                            .traceWithStack("CVSProject.locateEntry: NO SLASH IN '"
3623:                                    + fullPath + "'");
3624:                    entry = this .rootEntry.locateEntry(fullPath);
3625:                } else {
3626:                    String name = fullPath.substring(index + 1);
3627:                    String localDirectory = fullPath.substring(0, index + 1);
3628:
3629:                    CVSEntry parentEntry = this 
3630:                            .getPathTableEntry(localDirectory);
3631:
3632:                    if (parentEntry == null) {
3633:                        CVSTracer
3634:                                .traceWithStack("CVSProject.locateEntry: LOCAL DIRECTORY '"
3635:                                        + localDirectory + "' NOT IN TABLE");
3636:                    } else {
3637:                        if (false)
3638:                            CVSTracer.traceIf(false,
3639:                                    "CVSProject.locateEntry: PARENT '"
3640:                                            + parentEntry.getFullName() + "'");
3641:
3642:                        entry = parentEntry.locateEntry(name);
3643:                    }
3644:                }
3645:
3646:                if (CVSProject.deepDebug)
3647:                    CVSTracer.traceIf(true,
3648:                            "CVSProject.locateEntry: fullPath '"
3649:                                    + fullPath
3650:                                    + "' resulting entry '"
3651:                                    + (entry == null ? "(null)" : entry
3652:                                            .getFullName()));
3653:
3654:                return entry;
3655:            }
3656:
3657:            public boolean ensureEntryHierarchy(String localDirectory,
3658:                    String repository) {
3659:                if (CVSProject.deepDebug)
3660:                    CVSTracer.traceIf(true,
3661:                            "CVSProject.ENSUREEntryHierarchy:\n"
3662:                                    + "   localDirectory '" + localDirectory
3663:                                    + "'\n" + "   repository '" + repository);
3664:
3665:                if (localDirectory.equals("./")) {
3666:                    if (this .rootEntry == null) {
3667:                        if (CVSProject.deepDebug)
3668:                            CVSTracer.traceIf(true,
3669:                                    "CVSProject.ENSUREEntryHierarchy: ESTABLISH '.' ROOT ENTRY\n"
3670:                                            + "   repository '" + repository);
3671:
3672:                        this .establishRootEntry(repository);
3673:
3674:                        return true;
3675:                    } else {
3676:                        // REVIEW
3677:                        // Should this verify the 'repository' exists?!
3678:                        // Given the note below, I do not think there is
3679:                        // any methd that would properly parse this case.
3680:                        // Ergo, we hope it can only occur if the entry
3681:                        // already exists.
3682:                        //
3683:                        CVSTracer.traceIf(true,
3684:                                "CVSProject.ENSUREEntryHierarchy: IGNORING '.' localDirectory!\n"
3685:                                        + "   repository '" + repository);
3686:                        return true;
3687:                    }
3688:                }
3689:
3690:                CVSEntry lookupEntry = this .getPathTableEntry(localDirectory);
3691:
3692:                // The local directory is the Path Table.
3693:                // Thus, the entry must already exist, return.
3694:                //
3695:                if (lookupEntry != null)
3696:                    return true;
3697:
3698:                //
3699:                // We are going to get response items that sometimes have no
3700:                // corresponding entry in the Path Table. Further, these entries
3701:                // have no corresponding hierarchy in the CVSEntry tree, which
3702:                // in turn implies no nodes in the EntryTree of jCVS.
3703:                //
3704:                // This code will attempt to parse the incoming item and ensure
3705:                // that the CVSEntry's in the item's path exist.
3706:                //
3707:                // We have updated this code to make a HUGE NEW ASSUMPTION!!!!!
3708:                //
3709:                // We are assuming that we will never see a request to ensure a
3710:                // hierarchy in which the parent nodes do not exist. In other
3711:                // words, we should never see a case where the 'local directory'
3712:                // of the item contains more than one subdirectory beyond what
3713:                // is "currently ensured". In other words, items will not be
3714:                // seen for a subdirectory that is more than one level below
3715:                // a level we already have ensured.
3716:                //
3717:                // If that assumption is wrong, we are going to have to make
3718:                // another assumption that the only time these paths would be
3719:                // out of sync is when a module alias is used. In these cases,
3720:                // the paths MUST be in sync when working back from the end.
3721:                // I can not think of a case in which this would not be true.
3722:                //
3723:                // Example: ( module alias "api api/machdep/linux" )
3724:                //
3725:                //   Entry           LocalDir               Repository
3726:                //   ROOT            ./                     /cvs/
3727:                //     api           ./api/                 /cvs/api/machdep/linux
3728:                //        include    ./api/include/         /cvs/api/machdep/linux/include
3729:                //
3730:                // In that example, if we got 'include' before we got 'api', we would have
3731:                // to work back from include up to './', and assume that the top level entry
3732:                // subsumes the remainder of the repository path as its own, since only
3733:                // aliases should have this case, and aliases can only apply to the top level.
3734:                //
3735:
3736:                if (CVSProject.deepDebug)
3737:                    CVSTracer.traceIf(true,
3738:                            "CVSProject.ensureEntryHierarchy: START LOOP\n"
3739:                                    + "   localDirectory '" + localDirectory
3740:                                    + "'\n" + "   repository     '"
3741:                                    + repository + "'");
3742:
3743:                CVSEntry curEntry = this .rootEntry;
3744:
3745:                // FIRST, we work FORWARD eliminating as much of the path as
3746:                //        we can find in the Path Table.
3747:                //
3748:                for (;;) {
3749:                    int length = curEntry.getLocalDirectory().length();
3750:                    int slashIdx = localDirectory.indexOf("/", length);
3751:
3752:                    if (CVSProject.deepDebug)
3753:                        CVSTracer.traceIf(true,
3754:                                "CVSProject.ensureEntryHierarchy: TOP LOOP\n"
3755:                                        + "   length = " + length
3756:                                        + "  slashIdx = " + slashIdx + "\n"
3757:                                        + "   curEntry: "
3758:                                        + curEntry.dumpString("   "));
3759:
3760:                    if (slashIdx == -1)
3761:                        break;
3762:
3763:                    String subLocal = localDirectory.substring(0, slashIdx + 1);
3764:                    CVSEntry pathEntry = this .getPathTableEntry(subLocal);
3765:
3766:                    if (CVSProject.deepDebug)
3767:                        CVSTracer.traceIf(true,
3768:                                "CVSProject.ensureEntryHierarchy: "
3769:                                        + "LOOP lookup path '"
3770:                                        + subLocal
3771:                                        + "' returns:\n"
3772:                                        + (pathEntry == null ? "NULL"
3773:                                                : pathEntry.dumpString("   ")));
3774:
3775:                    if (pathEntry == null)
3776:                        break;
3777:
3778:                    curEntry = pathEntry;
3779:                }
3780:                /*
3781:                 index slashCnt = CVSCUtilities.getSlashCount( subLocal );
3782:                 if ( slashCnt == 1 )
3783:                 {
3784:                 // GREAT! We have a simple one level entry, which is simple!
3785:                 this.pathTable.put( localDirectory, repository );
3786:
3787:                 String name =
3788:                 CVSCUtilities.stripFinalSlash
3789:                 ( localDirectory.substring
3790:                 ( curEntry.getRepository().length() ) );
3791:
3792:                 if ( CVSProject.deepDebug )
3793:                 CVSTracer.traceIf( true,
3794:                 "CVSProject.ensureEntryHierarchy: ADD NEW ENTRY:\n"
3795:                 + "   name       '" + name + "\n"
3796:                 + "   repository '" + repository + "'\n"
3797:                 + "   localdir   '" + localDirectory + "'" );
3798:
3799:                 CVSEntry newEntry = new CVSEntry();
3800:                 newEntry.setName( name );
3801:                 newEntry.setRepository( repository );
3802:                 newEntry.setLocalDirectory( localDirectory );
3803:                 newEntry.setVersion( "" );
3804:                 newEntry.setTimestamp( "" );
3805:                 newEntry.setOptions( "" );
3806:                 newEntry.setTag( "" );
3807:                 newEntry.setDirty( true );
3808:
3809:                 // NOTE setDirectoryEntryList() sets 'isDir'-ness of entry.
3810:                 newEntry.setDirectoryEntryList( new CVSEntryVector() );
3811:
3812:                 if ( CVSProject.deepDebug )
3813:                 CVSTracer.traceIf( true,
3814:                 "CVSProject.ensureEntryHierarchy: NEW ENTRY =\n"
3815:                 + newEntry.dumpSting( "   " ) );
3816:
3817:                 curEntry.appendEntry( newEntry );
3818:                 return true;
3819:                 }
3820:                 */
3821:                //
3822:                // Ok. We now have a 'local directory' subpath that does not exist
3823:                // yet. We will work backwards building the elements in the path,
3824:                // into a Vector. Then, we will roll then out forwards.
3825:                //
3826:                Vector elements = new Vector();
3827:
3828:                String workingRepos = CVSCUtilities
3829:                        .ensureFinalSlash(repository);
3830:
3831:                int reposIdx = workingRepos.length() - 1;
3832:                int localIdx = localDirectory.length() - 1;
3833:
3834:                if (CVSProject.deepDebug)
3835:                    CVSTracer.traceIf(true,
3836:                            "CVSProject.ensureEntryHierarchy: START MULTI LEVEL LOOP\n"
3837:                                    + "         reposIdx =  " + reposIdx
3838:                                    + "  localIdx =  " + localIdx + "\n"
3839:                                    + "   localDirectory = '" + localDirectory
3840:                                    + "'\n" + "     workingRepos = '"
3841:                                    + workingRepos + "'\n"
3842:                                    + "         curEntry = \n"
3843:                                    + curEntry.dumpString("   "));
3844:
3845:                for (;;) {
3846:                    int newRepIdx = workingRepos.lastIndexOf("/", reposIdx - 1);
3847:                    int newLocIdx = localDirectory.lastIndexOf("/",
3848:                            localIdx - 1);
3849:
3850:                    if (CVSProject.deepDebug)
3851:                        CVSTracer.traceIf(true,
3852:                                "CVSProject.ensureEntryHierarchy: PARSE PATH LOOP\n"
3853:                                        + "    reposIdx =  " + reposIdx
3854:                                        + "    localIdx =  " + localIdx + "\n"
3855:                                        + "   newRepIdx =  " + newRepIdx
3856:                                        + "   newLocIdx =  " + newLocIdx);
3857:
3858:                    String name = localDirectory.substring(newLocIdx + 1,
3859:                            localIdx);
3860:                    String subRepos = workingRepos.substring(0, reposIdx); // drop final slash
3861:                    String subLocal = localDirectory.substring(0, localIdx + 1); // include final slash
3862:
3863:                    if (CVSProject.deepDebug)
3864:                        CVSTracer.traceIf(true,
3865:                                "CVSProject.ensureEntryHierarchy: CHECK PATH\n"
3866:                                        + "       name = '" + name + "'\n"
3867:                                        + "   subRepos = '" + subRepos + "'\n"
3868:                                        + "   subLocal = '" + subLocal + "'");
3869:
3870:                    if (subLocal.equals(curEntry.getLocalDirectory())) {
3871:                        if (CVSProject.deepDebug)
3872:                            CVSTracer
3873:                                    .traceIf(true,
3874:                                            "CVSProject.ensureEntryHierarchy: HIT CUR-ENTRY, BREAK");
3875:                        break;
3876:                    }
3877:
3878:                    if (CVSProject.deepDebug)
3879:                        CVSTracer.traceIf(true,
3880:                                "CVSProject.ensureEntryHierarchy: ADDED PATH!");
3881:
3882:                    String[] parms = { name, subRepos, subLocal };
3883:                    elements.addElement(parms);
3884:
3885:                    reposIdx = newRepIdx;
3886:                    localIdx = newLocIdx;
3887:                }
3888:
3889:                for (int i = elements.size() - 1; i >= 0; --i) {
3890:                    String[] parms = (String[]) elements.elementAt(i);
3891:
3892:                    CVSEntry newEntry = new CVSEntry();
3893:                    newEntry.setDirty(true);
3894:                    newEntry.setName(parms[0]);
3895:                    newEntry.setRepository(parms[1]);
3896:                    newEntry.setLocalDirectory(parms[2]);
3897:                    newEntry.setVersion("");
3898:                    newEntry.setTimestamp("");
3899:                    newEntry.setOptions("");
3900:                    newEntry.setTag("");
3901:
3902:                    // NOTE setDirectoryEntryList() sets 'isDir'-ness of entry.
3903:                    //      If we do not do this, the the getFullPathName() used
3904:                    //      to get the working directory will include the dir's
3905:                    //      name in the path, which is redundant and throws off
3906:                    //      the algorithm by a directory level!
3907:                    //
3908:                    newEntry.setDirectoryEntryList(new CVSEntryVector());
3909:
3910:                    //
3911:                    // NOTE
3912:                    //
3913:                    // If there is an existing Entries file in place, then we have
3914:                    // the case where we are picking up something that is laying on
3915:                    // top of an existing working directory. This is almost always
3916:                    // the case of the user performing a checkout of another module
3917:                    // on top of an existing working directory. In this case, we
3918:                    // must read in the existing Entries file, or we will end up
3919:                    // over-writing the file when we save the current hierarchy!
3920:                    //
3921:                    File workingDirF = new File(CVSCUtilities.exportPath(this 
3922:                            .getLocalRootDirectory()));
3923:
3924:                    workingDirF = new File(workingDirF, CVSCUtilities
3925:                            .exportPath(newEntry.getFullPathName()));
3926:
3927:                    CVSEntryVector entries = this .readEntriesFile(newEntry,
3928:                            workingDirF);
3929:
3930:                    if (CVSProject.deepDebug)
3931:                        CVSTracer
3932:                                .traceIf(true,
3933:                                        "CVSProject.ensureEntryHierarchy: "
3934:                                                + "Entries = "
3935:                                                + entries
3936:                                                + ", size="
3937:                                                + (entries == null ? 0
3938:                                                        : entries.size())
3939:                                                + ", at '"
3940:                                                + workingDirF.getAbsolutePath()
3941:                                                + "'");
3942:
3943:                    if (entries != null) {
3944:                        newEntry.setDirectoryEntryList(entries);
3945:                    }
3946:
3947:                    if (CVSProject.deepDebug)
3948:                        CVSTracer.traceIf(true,
3949:                                "CVSProject.ensureEntryHierarchy: "
3950:                                        + "MULTI LEVEL APPEND NEW ENTRY\n"
3951:                                        + "   CUR ENTRY:"
3952:                                        + curEntry.dumpString("   ") + "\n"
3953:                                        + "   NEW ENTRY:"
3954:                                        + newEntry.dumpString("   "));
3955:
3956:                    this .pathTable.put(newEntry.getLocalDirectory(), newEntry);
3957:
3958:                    curEntry.appendEntry(newEntry);
3959:                    curEntry = newEntry;
3960:                }
3961:
3962:                return true;
3963:            }
3964:
3965:            // subpath is the local path up to the name.
3966:            public boolean ensureProperWorkingDirectory(String localRoot,
3967:                    String subPath, boolean ensureAdmin) {
3968:                int index;
3969:                boolean result = true;
3970:
3971:                if (CVSProject.deepDebug)
3972:                    CVSTracer.traceIf(true,
3973:                            "CVSClient.ENSURE Proper WORKING Directory:\n"
3974:                                    + "    localRoot '" + localRoot + "'\n"
3975:                                    + "      subPath '" + subPath + "'\n"
3976:                                    + "    ensureAdm '" + ensureAdmin + "'");
3977:
3978:                subPath = CVSCUtilities.stripFinalSlash(subPath);
3979:                if (subPath.startsWith("./"))
3980:                    subPath = subPath.substring(2);
3981:
3982:                String remainder = subPath;
3983:
3984:                for (; result && remainder.length() > 0;) {
3985:                    index = remainder.indexOf('/');
3986:                    if (index < 0) {
3987:                        subPath = remainder;
3988:                        remainder = "";
3989:                    } else {
3990:                        subPath = remainder.substring(0, index);
3991:                        remainder = remainder.substring(index + 1);
3992:                    }
3993:
3994:                    // UNDONE separator
3995:                    File dir = new File(localRoot + "/" + subPath);
3996:
3997:                    if (!dir.exists())
3998:                        dir.mkdir();
3999:
4000:                    if (!dir.exists()) {
4001:                        result = false;
4002:                        CVSLog.logMsg("ERROR could not create local path '"
4003:                                + dir.getPath() + "'");
4004:                    } else if (!dir.isDirectory()) {
4005:                        result = false;
4006:                        CVSLog.logMsg("ERROR local directory '" + dir.getPath()
4007:                                + "' is not a directory!");
4008:                    } else if (result && ensureAdmin) {
4009:                        File adminDir = // UNDONE separator
4010:                        new File(dir.getPath() + "/CVS");
4011:
4012:                        if (CVSProject.deepDebug)
4013:                            CVSTracer.traceIf(true,
4014:                                    "CVSClient.ensureProperWorkingDirectory: ADMINDIR '"
4015:                                            + adminDir.getPath() + "'");
4016:
4017:                        if (!adminDir.exists())
4018:                            adminDir.mkdir();
4019:
4020:                        if (!adminDir.exists()) {
4021:                            result = false;
4022:                            CVSLog.logMsg("ERROR could not create Admin path '"
4023:                                    + this .localAdminDirFile.getPath() + "'");
4024:                        }
4025:                    }
4026:
4027:                    // UNDONE separator
4028:                    localRoot = localRoot + "/" + subPath;
4029:                }
4030:
4031:                return result;
4032:            }
4033:
4034:            public boolean ensureLocalTree(File localFile, boolean ensureAdmin) {
4035:                int index;
4036:                boolean result = true;
4037:
4038:                String localPath = localFile.getPath();
4039:
4040:                String localRoot = CVSCUtilities
4041:                        .exportPath(this .localRootDirectory);
4042:
4043:                index = localPath.lastIndexOf(File.separatorChar);
4044:                if (index < 0) {
4045:                    return true;
4046:                }
4047:
4048:                String localSub = localPath.substring(0, index);
4049:
4050:                if (!CVSCUtilities.isSubpathInPath(localRoot, localSub)) {
4051:                    CVSLog
4052:                            .logMsg("CVSClient.ensureLocalTree:  LOCAL SUBDIR IS NOT IN ROOT!!\n"
4053:                                    + "   localRoot   '"
4054:                                    + localRootDirectory
4055:                                    + "'\n"
4056:                                    + "   localSubDir '"
4057:                                    + localSub
4058:                                    + "'");
4059:                    result = false;
4060:                }
4061:
4062:                // REVIEW
4063:                //
4064:                // Per Thorsten Ludewig <T.Ludewig@FH-Wolfenbuettel.DE>, who
4065:                // reported that this eliminated an index out of bounds exception,
4066:                // which I think other users were reporting also.
4067:                //
4068:                // Need to review to make sure that "./" is the correct substitution.
4069:                //
4070:                if (localSub.equals(localRoot)) {
4071:                    localSub = "./";
4072:                } else {
4073:                    localSub = localSub.substring(localRoot.length() + 1);
4074:                }
4075:
4076:                if (CVSProject.deepDebug)
4077:                    CVSTracer.traceIf(true,
4078:                            "CVSClient.ensureLocalTree: tempFile '"
4079:                                    + localFile.getPath() + "' localPath '"
4080:                                    + localPath + "' --> '" + localSub + "'");
4081:
4082:                result = this .ensureProperWorkingDirectory(
4083:                        this .localRootDirectory, localSub, ensureAdmin);
4084:
4085:                return result;
4086:            }
4087:
4088:            public void moveLocalFile(File localFile, String versionStr)
4089:                    throws CVSFileException {
4090:                //
4091:                // REVIEW
4092:                // UNDONE
4093:                // Should we capitualate and use the 'standard' notation
4094:                // of '.#name.version' (e.g., '.#main.c.1.4')? I prefer
4095:                // this naming scheme (e.g., '#main.c.1.4').
4096:                //
4097:                String localPath = localFile.getPath();
4098:
4099:                String base = "";
4100:                String name = localPath;
4101:                int index = localPath.lastIndexOf('/');
4102:                if (index >= 0) {
4103:                    base = localPath.substring(0, index);
4104:                    name = localPath.substring(index + 1);
4105:                }
4106:
4107:                String newPath = base + "/" + "#" + name + "." + versionStr;
4108:
4109:                CVSTracer.traceIf(CVSProject.overTraceProcessing,
4110:                        "CVSProject.moveLocalFile: move '"
4111:                                + localFile.getPath() + "' to '" + newPath
4112:                                + "'");
4113:
4114:                File toFile = new File(newPath);
4115:
4116:                boolean result = localFile.renameTo(toFile);
4117:
4118:                CVSTracer.traceIf(false,
4119:                        "CVSProject.moveLocalFile: rename returns '" + result
4120:                                + "'");
4121:
4122:                if (!result)
4123:                    throw new CVSFileException("failed renaming '"
4124:                            + localFile.getPath() + "' to '" + toFile.getPath()
4125:                            + "'");
4126:            }
4127:
4128:            public boolean updateLocalFile(CVSResponseItem item,
4129:                    CVSEntry entry, File localFile) {
4130:                boolean result = true;
4131:
4132:                int trans = CVSCUtilities.computeTranslation(entry);
4133:
4134:                result = this .copyFile(item.getFile(), localFile, trans, item
4135:                        .isGZIPed());
4136:
4137:                return result;
4138:            }
4139:
4140:            public boolean copyFile(File from, File to, int translation,
4141:                    boolean isGZIPed) {
4142:                boolean result = false;
4143:
4144:                CVSTracer
4145:                        .traceIf(
4146:                                CVSProject.overTraceProcessing,
4147:                                "CVSProject.copyFile: from '"
4148:                                        + from.getPath()
4149:                                        + "' to '"
4150:                                        + to.getPath()
4151:                                        + "' trans '"
4152:                                        + (translation == CVSClient.TRANSLATE_ASCII ? "ASCII"
4153:                                                : "NONE") + "' gzip-ed? '"
4154:                                        + isGZIPed + "'");
4155:
4156:                switch (translation) {
4157:                case CVSClient.TRANSLATE_ASCII:
4158:                    result = this .copyFileAscii(from, to, isGZIPed);
4159:                    break;
4160:
4161:                case CVSClient.TRANSLATE_NONE:
4162:                default:
4163:                    result = this .copyFileRaw(from, to, isGZIPed);
4164:                    break;
4165:                }
4166:
4167:                return result;
4168:            }
4169:
4170:            public boolean copyFileAscii(File from, File to, boolean isGZIPed) {
4171:                boolean ok = true;
4172:
4173:                BufferedReader in = null;
4174:                BufferedWriter out = null;
4175:
4176:                String line = null;
4177:
4178:                try {
4179:                    if (isGZIPed) {
4180:                        in = this .new NewLineReader(new InputStreamReader(
4181:                                new GZIPInputStream(new FileInputStream(from))));
4182:                    } else {
4183:                        in = new NewLineReader(new FileReader(from));
4184:                    }
4185:                } catch (IOException ex) {
4186:                    in = null;
4187:                    ok = false;
4188:                    CVSLog
4189:                            .logMsg("CVSProject.copyFileAscii: failed creating in reader: "
4190:                                    + ex.getMessage());
4191:                }
4192:
4193:                if (ok)
4194:                    try {
4195:                        out = new BufferedWriter(new FileWriter(to));
4196:                    } catch (IOException ex) {
4197:                        out = null;
4198:                        ok = false;
4199:                        CVSLog
4200:                                .logMsg("CVSProject.copyFileAscii: failed creating out writer: "
4201:                                        + ex.getMessage());
4202:                    }
4203:
4204:                if (out == null || in == null) {
4205:                    ok = false;
4206:                    CVSLog.logMsg("CVSProject.copyFileAscii: failed creating '"
4207:                            + (out == null ? "output writer" : "input reader")
4208:                            + "'");
4209:                }
4210:
4211:                if (ok) {
4212:                    for (;;) {
4213:                        try {
4214:                            line = in.readLine();
4215:
4216:                            if (line == null)
4217:                                break;
4218:
4219:                            out.write(line);
4220:
4221:                            // NB-eol
4222:                            // readLine now returns the EOL also.  Stops cvsc from
4223:                            // adding EOL to binaries checked in as ascii and files
4224:                            // without eol at eof.
4225:                            //
4226:                            // out.newLine();
4227:                        } catch (IOException ex) {
4228:                            CVSLog
4229:                                    .logMsg("CVSProject.copyFileAscii: failed during copy: "
4230:                                            + ex.getMessage());
4231:                            ok = false;
4232:                            break;
4233:                        }
4234:                    }
4235:
4236:                    try {
4237:                        out.flush();
4238:                    } catch (IOException ex) {
4239:                        CVSLog
4240:                                .logMsg("CVSProject.copyFileAscii: failed flushing output: "
4241:                                        + ex.getMessage());
4242:                        ok = false;
4243:                    }
4244:                }
4245:
4246:                try {
4247:                    if (in != null)
4248:                        in.close();
4249:                    if (out != null)
4250:                        out.close();
4251:                } catch (IOException ex) {
4252:                    CVSLog
4253:                            .logMsg("CVSProject.copyFileAscii: failed closing files: "
4254:                                    + ex.getMessage());
4255:                    ok = false;
4256:                }
4257:
4258:                return ok;
4259:            }
4260:
4261:            public boolean copyFileRaw(File from, File to, boolean isGZIPed) {
4262:                int bytes;
4263:                long fileSize;
4264:                boolean ok = true;
4265:
4266:                BufferedInputStream in = null;
4267:                BufferedOutputStream out = null;
4268:
4269:                String line = null;
4270:
4271:                try {
4272:                    if (isGZIPed) {
4273:                        in = new BufferedInputStream(new GZIPInputStream(
4274:                                new FileInputStream(from)));
4275:                    } else {
4276:                        in = new BufferedInputStream(new FileInputStream(from));
4277:                    }
4278:                } catch (Exception ex) {
4279:                    in = null;
4280:                    ok = false;
4281:                    CVSLog
4282:                            .logMsg("CVSProject.copyFileRaw: failed creating in reader: "
4283:                                    + ex.getMessage());
4284:                }
4285:
4286:                if (ok) {
4287:                    try {
4288:                        out = new BufferedOutputStream(new FileOutputStream(to));
4289:                    } catch (Exception ex) {
4290:                        out = null;
4291:                        ok = false;
4292:                        CVSLog
4293:                                .logMsg("CVSProject.copyFileRaw: failed creating out writer: "
4294:                                        + ex.getMessage());
4295:                    }
4296:                }
4297:
4298:                if (out == null || in == null) {
4299:                    ok = false;
4300:                    CVSLog.logMsg("CVSProject.copyFileRaw: failed creating '"
4301:                            + (out == null ? "output writer" : "input reader")
4302:                            + "'");
4303:                }
4304:
4305:                if (ok) {
4306:                    byte[] buffer;
4307:                    buffer = new byte[8192];
4308:
4309:                    fileSize = from.length();
4310:                    for (;;) {
4311:                        try {
4312:                            bytes = in.read(buffer, 0, 8192);
4313:                        } catch (IOException ex) {
4314:                            ok = false;
4315:                            CVSLog.logMsg("CVSProject.copyFileRaw: "
4316:                                    + "ERROR reading file data:\n   "
4317:                                    + ex.getMessage());
4318:                            break;
4319:                        }
4320:
4321:                        if (bytes < 0)
4322:                            break;
4323:
4324:                        try {
4325:                            out.write(buffer, 0, bytes);
4326:                        } catch (IOException ex) {
4327:                            ok = false;
4328:                            CVSLog.logMsg("CVSProject.copyFileRaw: "
4329:                                    + "ERROR writing output file:\n   "
4330:                                    + ex.getMessage());
4331:                            break;
4332:                        }
4333:                    }
4334:                }
4335:
4336:                try {
4337:                    if (in != null)
4338:                        in.close();
4339:                    if (out != null)
4340:                        out.close();
4341:                } catch (IOException ex) {
4342:                    CVSLog
4343:                            .logMsg("CVSProject.copyFileRaw: failed closing files: "
4344:                                    + ex.getMessage());
4345:                    ok = false;
4346:                }
4347:
4348:                return ok;
4349:            }
4350:
4351:            private class NewLineReader extends BufferedReader {
4352:                public NewLineReader(Reader in) {
4353:                    super (in);
4354:                }
4355:
4356:                public String readLine() {
4357:                    char ch;
4358:                    StringBuffer line = new StringBuffer(132);
4359:
4360:                    try {
4361:                        for (;;) {
4362:                            int inByte = this .read();
4363:                            if (inByte == -1) {
4364:                                if (line.length() == 0)
4365:                                    line = null;
4366:                                break;
4367:                            }
4368:
4369:                            ch = (char) inByte;
4370:                            if (ch == 0x0A) {
4371:                                // mtt - 21.02.02 
4372:                                // we need to append the correct line end
4373:                                // for the platform we are running under.
4374:                                //
4375:                                // NB-eol
4376:                                // we need to not wrongly assume later
4377:                                // the line always ends in eol.
4378:                                //
4379:                                line.append(System
4380:                                        .getProperty("line.separator"));
4381:                                break;
4382:                            }
4383:
4384:                            line.append(ch);
4385:                        }
4386:                    } catch (IOException ex) {
4387:                        line = null;
4388:                    }
4389:
4390:                    return (line != null ? line.toString() : null);
4391:                }
4392:            }
4393:
4394:            //
4395:            // CVS USER INTERFACE METHODS
4396:            //
4397:
4398:            // Currently, we stub these out.
4399:            public void uiDisplayProgressMsg(String message) {
4400:            }
4401:
4402:            public void uiDisplayProgramError(String error) {
4403:            }
4404:
4405:            public void uiDisplayResponse(CVSResponse response) {
4406:            }
4407:
4408:            //
4409:            // END OF CVS USER INTERFACE METHODS
4410:            //
4411:
4412:            public String toString() {
4413:                return "CVSProject: name '" + this .repository + "'";
4414:            }
4415:
4416:            public StringBuffer dumpCVSProject(StringBuffer buf,
4417:                    String description) {
4418:                buf
4419:                        .append("##############################################################\n");
4420:                buf.append("#\n");
4421:                buf.append("# CVSProject  '").append(this .repository).append(
4422:                        "'\n");
4423:                buf.append("#\n");
4424:                buf.append("# Description '").append(description).append("'\n");
4425:                buf.append("#\n");
4426:                buf
4427:                        .append("##############################################################\n");
4428:
4429:                buf.append("\n");
4430:
4431:                buf.append("  valid?      '").append(this .valid).append("'\n");
4432:                buf.append("  isPServer?  '").append(this .isPServer).append(
4433:                        "'\n");
4434:                buf.append("  allowsGzip? '").append(this .allowGzipFileMode)
4435:                        .append("'\n");
4436:                buf.append("  gzipLevel   '").append(this .gzipStreamLevel)
4437:                        .append("'\n");
4438:                buf.append("  connMethod  '").append(this .connMethod).append(
4439:                        "'\n");
4440:                buf.append("  serverCmd   '").append(this .serverCommand)
4441:                        .append("'\n");
4442:                buf.append("  rshProcess  '").append(this .rshProcess).append(
4443:                        "'\n");
4444:                buf.append("  userName    '").append(this .userName).append(
4445:                        "'\n");
4446:                buf.append("  tempPath    '").append(this .tempPath).append(
4447:                        "'\n");
4448:                buf.append("  repository  '").append(this .repository).append(
4449:                        "'\n");
4450:                buf.append("  rootDir     '").append(this .rootDirectory)
4451:                        .append("'\n");
4452:                buf.append("  localRoot   '").append(this .localRootDirectory)
4453:                        .append("'\n");
4454:
4455:                buf.append("\n");
4456:
4457:                buf.append("------- Path Table -------\n");
4458:
4459:                buf.append("\n");
4460:
4461:                Enumeration numer = this .pathTable.keys();
4462:                for (; numer.hasMoreElements();) {
4463:                    String key = (String) numer.nextElement();
4464:                    CVSEntry val = (CVSEntry) this .pathTable.get(key);
4465:                    buf.append(key).append(" =\n\n   ");
4466:                    buf.append(val.dumpString()).append("\n\n");
4467:                }
4468:
4469:                buf.append("\n");
4470:
4471:                buf.append("------- Root Entry -------\n");
4472:                if (this .rootEntry == null) {
4473:                    buf.append("   Root Entry Is Null.\n");
4474:                } else {
4475:                    buf.append("  ").append(this .rootEntry.dumpString())
4476:                            .append("\n");
4477:                }
4478:
4479:                buf.append("\n");
4480:
4481:                buf.append("------- ENTRY TREE -------\n");
4482:
4483:                buf.append("\n");
4484:
4485:                buf.append("").append("./").append("\n");
4486:                this .dumpEntry(buf, "   ", this .rootEntry);
4487:
4488:                // DUMP SET VARIABLES
4489:
4490:                // DUMP CVSIGNORE
4491:
4492:                // DUMP ENTRY TREE...
4493:
4494:                // DUMP CLIENT
4495:
4496:                return buf;
4497:            }
4498:
4499:            public StringBuffer dumpEntry(StringBuffer buf, String prefix,
4500:                    CVSEntry dirEntry) {
4501:                CVSEntryVector entries = dirEntry.getEntryList();
4502:
4503:                for (int i = 0, sz = entries.size(); i < sz; ++i) {
4504:                    CVSEntry entry = entries.getEntryAt(i);
4505:
4506:                    buf.append(prefix).append(entry.getFullName()).append("\n");
4507:
4508:                    if (entry.isDirectory()) {
4509:                        this .dumpEntry(buf, prefix + "   ", entry);
4510:                    }
4511:                }
4512:
4513:                return buf;
4514:            }
4515:
4516:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.