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:
0032: /**
0033: * The CVSRequest class is used to encapsulate a complete
0034: * description of a CVS server request. Capable of parsing
0035: * a simple string to define a request, CVSRequests are
0036: * often built by configuration properties. Once a CVRequest
0037: * is built and filled in, it is handed to a CVSClient for
0038: * processing. Once the processing is completed, the CVSClient
0039: * will return a CVSResponse containing the results of the
0040: * request.
0041: *
0042: * @version $Revision: 2.9 $
0043: * @author Timothy Gerard Endres, <time@gjt.org>.
0044: * @see CVSClient
0045: * @see CVSProject
0046: */
0047:
0048: public class CVSRequest extends Object {
0049: static public final String RCS_ID = "$Id: CVSRequest.java,v 2.9 2003/07/27 01:08:32 time Exp $";
0050: static public final String RCS_REV = "$Revision: 2.9 $";
0051:
0052: static public final int METHOD_INETD = 1;
0053: static public final int METHOD_RSH = 2;
0054: static public final int METHOD_SSH = 3;
0055:
0056: static private final int ES_FIRST = 0;
0057:
0058: static public final int ES_NONE = ES_FIRST;
0059: static public final int ES_ALL = ES_NONE + 1;
0060: static public final int ES_SEL = ES_ALL + 1;
0061: static public final int ES_SELALL = ES_SEL + 1;
0062: static public final int ES_ALLMOD = ES_SELALL + 1;
0063: static public final int ES_SELMOD = ES_ALLMOD + 1;
0064: static public final int ES_ALLLOST = ES_SELMOD + 1;
0065: static public final int ES_SELLOST = ES_ALLLOST + 1;
0066: static public final int ES_ALLUNC = ES_SELLOST + 1;
0067: static public final int ES_SELUNC = ES_ALLUNC + 1;
0068: static public final int ES_USER = ES_SELUNC + 1;
0069: static public final int ES_NEW = ES_USER + 1;
0070: static public final int ES_POPUP = ES_NEW + 1;
0071:
0072: static private final int ES_LAST = ES_POPUP;
0073:
0074: private PrintStream traceStream;
0075:
0076: /**
0077: * If true, the request phase of the CVS command will be
0078: * traced on stderr.
0079: */
0080: public boolean traceRequest;
0081: /**
0082: * If true, the response phase of the CVS command will be
0083: * traced on stderr.
0084: */
0085: public boolean traceResponse;
0086: /**
0087: * If true, the processing phase of the CVS command will be
0088: * traced on stderr.
0089: */
0090: public boolean traceProcessing;
0091: /**
0092: * If true, all input and output data (TCP bytes) will be traced.
0093: */
0094: public boolean traceTCPData;
0095:
0096: private String vfReason;
0097:
0098: /**
0099: * This is set by the "Valid-requests" cvs request.
0100: * If true, the server understands 'Unchanged' requests.
0101: */
0102: public boolean useUnchanged;
0103:
0104: /**
0105: * This is set by the "Valid-requests" cvs request.
0106: * If true, the server understands 'Directory' requests.
0107: */
0108: public boolean useDirectory;
0109:
0110: /**
0111: * This determines where cvs commands are executed.
0112: * If true, the command is run in the 'current directory'.
0113: * If false, the command is run at the 'top level'.
0114: */
0115: public boolean execInCurDir;
0116:
0117: /**
0118: * Determines if this request will send the 'Entry' requests.
0119: */
0120: public boolean sendEntries;
0121:
0122: /**
0123: * Determines if this request will send 'Modified' requests
0124: * for files that are modified locally. If true, modified
0125: * files are uploaded via 'Modified'. If false, modified
0126: * files are treated as if they were unchanged.
0127: */
0128: public boolean sendModifieds;
0129:
0130: /**
0131: * Determines if this request will send the special empty 'Modified'
0132: * requests when a file is to be uploaded. If true, all 'Modified'
0133: * requests send a file size of zero to optimize the protocol when
0134: * the file's contents are not needed.
0135: */
0136: public boolean sendEmptyMods;
0137:
0138: /**
0139: * Determines if this request will send 'Argument 's.
0140: */
0141: public boolean sendArguments;
0142:
0143: /**
0144: * Determines if this request will send the 'Entry' list as 'files...'.
0145: */
0146: public boolean sendEntryFiles;
0147:
0148: /**
0149: * Determines if this request will send the 'Repository' list as 'module'.
0150: */
0151: public boolean sendModule;
0152:
0153: /**
0154: * Determines if this request will send the 'RootDirectory'.
0155: */
0156: public boolean sendRootDirectory;
0157:
0158: /**
0159: * Determines if this request should include the 'Notify' requests.
0160: */
0161: public boolean includeNotifies;
0162:
0163: /**
0164: * Determines if this request will only verify the login and then return.
0165: */
0166: public boolean verificationOnly;
0167:
0168: /**
0169: * Determines if this request will guarantee a '-m message' argument.
0170: * Actually getting the message from the user is the responsibility
0171: * of the code that uses the request, since CVSRequests have no clue
0172: * about how to get messages.
0173: */
0174: public boolean guaranteeMsg;
0175:
0176: /**
0177: * Determines if the output of the reponse (stderr & stdout) will
0178: * be redirected to a user specified file. It is the responsbility
0179: * of the code using the request to setup the output file.
0180: */
0181: public boolean redirectOutput;
0182:
0183: /**
0184: * Determines if this request should display the reponse.
0185: */
0186: public boolean displayReponse;
0187:
0188: /**
0189: * Determines if this request will handle 'Updated' responses.
0190: */
0191: public boolean handleUpdated;
0192:
0193: /**
0194: * Determines if this request will handle 'Merged' responses.
0195: */
0196: public boolean handleMerged;
0197:
0198: /**
0199: * Determines if this request will handle 'Copy-file' responses.
0200: */
0201: public boolean handleCopyFile;
0202:
0203: /**
0204: * Determines if this request will handle all entries related
0205: * responses ('New-entry', 'Remove-entry', etc.).
0206: */
0207: public boolean handleEntries;
0208:
0209: /**
0210: * Determines if this request will handle all settings related
0211: * responses ('Set-sticky', 'Clear-static-directory', etc.).
0212: */
0213: public boolean handleFlags;
0214:
0215: /**
0216: * If true, the reponse's status will be ignored and assumed
0217: * to be 'ok'. If false, the reponse's status will be set to
0218: * reflect the status returned by the server.
0219: */
0220: public boolean ignoreResult;
0221:
0222: /**
0223: * If true, reponses that try to overwrite existing updated
0224: * files will be allowed to overwrite if the file is in the
0225: * list of files sent to the server. If false, normal processing
0226: * occurs (no overwrites allowed).
0227: */
0228: public boolean allowOverWrites;
0229:
0230: /**
0231: * If true, the temporary files generated by this request will
0232: * not be deleted as usual. This is primarily for debugging.
0233: */
0234: public boolean saveTempFiles;
0235:
0236: /**
0237: * Reflects the current 'Sticky' setting in this request.
0238: */
0239: public boolean stickyIsSet;
0240:
0241: /**
0242: * Reflects the current 'Static-directory' setting in this request.
0243: */
0244: public boolean staticDirIsSet;
0245:
0246: /**
0247: * The 'Valid-requests' response string from the server.
0248: */
0249: public String validRequests;
0250:
0251: /**
0252: * Determines whether or not the server's reponse is queued.
0253: * If true, all responses will be queued and handed back in
0254: * the CVSResponse. If false, responses will be handed to the
0255: * 'responseHandler' for processing as they come from the server.
0256: */
0257: public boolean queueResponse;
0258:
0259: /**
0260: * The response handler. If this request does not use the
0261: * 'queue response' option, then this field must be set to
0262: * the CVSResponseHandler that will handle the responses
0263: * to this request.
0264: */
0265: public CVSResponseHandler responseHandler;
0266:
0267: /**
0268: * Force every file to go up as 'Modified'.
0269: */
0270: public boolean forceModifieds;
0271:
0272: /**
0273: * If > 0, sets Gzip-stream level. If 0, do not use Gzip-stream mode.
0274: */
0275: public int gzipStreamLevel;
0276:
0277: /**
0278: * If true, allow gzip-file-contents mode, otherwise suppress it.
0279: */
0280: public boolean allowGzipFileMode;
0281:
0282: /**
0283: * If true, send all files using gzip-file-contents mode.
0284: */
0285: public boolean gzipFileMode;
0286:
0287: /**
0288: * The 'Notification' vector. If this vector is not null
0289: * then it contains a vector if notification strings of the
0290: * format: 'File\tType\tTime\tHost\tWorkingDir\tWatches'.
0291: */
0292: public Vector notifies;
0293:
0294: /**
0295: * The 'Sticky' tags which are based in the 'Tag' file in
0296: * the admin directory are provided as a hashtable of tagspecs
0297: * where the key is the localDir ready for the 'Directory ' command.
0298: */
0299: private Hashtable stickys;
0300: private Hashtable statics;
0301:
0302: private String[] setVars;
0303:
0304: private int connMethod;
0305: private String rshProcess;
0306:
0307: private boolean isPServer;
0308: private String userName;
0309: private String password; // scrambled!
0310: private String serverCommand;
0311:
0312: private String updateProg;
0313: private String checkInProg;
0314:
0315: private int port;
0316: private String hostName;
0317:
0318: private String repository;
0319: private String rootDirectory;
0320: private String rootRepository;
0321: private String localDirectory;
0322:
0323: private String command;
0324: private int entrySelector;
0325:
0326: /**
0327: * Indicates the directory to run cvs command in.
0328: * This is used in conjunction with execInCurDir
0329: * to indicate the directory in which the command
0330: * should be executed.
0331: */
0332: private CVSEntry dirEntry;
0333:
0334: private CVSEntryVector entries;
0335: private CVSArgumentVector arguments;
0336: private CVSArgumentVector globalargs;
0337:
0338: private CVSUserInterface ui;
0339:
0340: private PrintWriter redirectWriter;
0341:
0342: public static String getConnMethodName(int method) {
0343: return (method == CVSRequest.METHOD_INETD ? "pserver"
0344: : (method == CVSRequest.METHOD_SSH ? "ssh" : "rsh"));
0345: }
0346:
0347: /**
0348: * Constructs a new CVSRequest object.
0349: */
0350: public CVSRequest() {
0351: super ();
0352:
0353: this .vfReason = null;
0354: this .traceStream = null;
0355: this .traceRequest = false;
0356: this .traceResponse = false;
0357: this .traceProcessing = false;
0358: this .traceTCPData = false;
0359:
0360: this .connMethod = CVSRequest.METHOD_INETD;
0361: this .rshProcess = null;
0362:
0363: this .isPServer = false;
0364: this .userName = "";
0365: this .password = "";
0366: this .serverCommand = "";
0367:
0368: this .useUnchanged = false;
0369: this .useDirectory = true;
0370:
0371: this .execInCurDir = false;
0372:
0373: this .sendEntries = false;
0374: this .sendModifieds = false;
0375: this .sendEmptyMods = false;
0376: this .sendArguments = false;
0377: this .sendEntryFiles = false;
0378: this .sendModule = false;
0379: this .sendRootDirectory = true;
0380: this .includeNotifies = true;
0381: this .verificationOnly = false;
0382: this .forceModifieds = false;
0383: this .gzipStreamLevel = 0;
0384: this .gzipFileMode = false;
0385: this .allowGzipFileMode = true;
0386:
0387: this .guaranteeMsg = false;
0388: this .redirectOutput = false;
0389: this .redirectWriter = null;
0390:
0391: this .displayReponse = false;
0392: this .allowOverWrites = false;
0393: this .handleUpdated = false;
0394: this .handleMerged = false;
0395: this .handleCopyFile = false;
0396: this .handleEntries = false;
0397: this .handleFlags = false;
0398: this .saveTempFiles = false;
0399:
0400: this .queueResponse = true;
0401: this .responseHandler = null;
0402:
0403: this .stickyIsSet = false;
0404: this .staticDirIsSet = false;
0405:
0406: this .updateProg = null;
0407: this .checkInProg = null;
0408:
0409: this .setVars = null;
0410:
0411: this .port = CVSClient.DEFAULT_CVS_PORT;
0412:
0413: this .hostName = null;
0414: this .repository = null;
0415: this .rootDirectory = null;
0416: this .localDirectory = null;
0417:
0418: this .command = null;
0419: this .entrySelector = CVSRequest.ES_SEL;
0420:
0421: this .ui = null;
0422: this .dirEntry = null;
0423: this .entries = null;
0424: this .arguments = null;
0425: this .globalargs = null;
0426: this .stickys = null;
0427: }
0428:
0429: protected void finalize() throws Throwable {
0430: super .finalize();
0431: this .endRedirection();
0432: }
0433:
0434: /**
0435: * Returns the request's server hostname.
0436: *
0437: * @return The string representing the request's server's hostname.
0438: */
0439: public String getHostName() {
0440: return this .hostName;
0441: }
0442:
0443: /**
0444: * Sets the request's server hostname. The hostname
0445: * is used to establish the connection with the CVS server.
0446: *
0447: * @param hostName The new hostname for the request's CVS Server.
0448: */
0449: public void setHostName(String hostName) {
0450: this .hostName = hostName;
0451: }
0452:
0453: /**
0454: * Returns the request's server port number.
0455: *
0456: * @return The request's CVS server port number.
0457: */
0458: public int getPort() {
0459: return this .port;
0460: }
0461:
0462: /**
0463: * Sets the request's server port number. The port number
0464: * is used to establish the connection with the CVS server.
0465: *
0466: * @param port The new port number for the request's CVS server.
0467: */
0468: public void setPort(int port) {
0469: this .port = port;
0470: }
0471:
0472: public boolean isPServer() {
0473: return this .isPServer;
0474: }
0475:
0476: public void setPServer(boolean isPServer) {
0477: this .isPServer = isPServer;
0478: }
0479:
0480: public CVSUserInterface getUserInterface() {
0481: return this .ui;
0482: }
0483:
0484: public void setUserInterface(CVSUserInterface ui) {
0485: this .ui = ui;
0486: }
0487:
0488: public String getUserName() {
0489: return this .userName;
0490: }
0491:
0492: public void setUserName(String userName) {
0493: this .userName = userName;
0494: }
0495:
0496: public String getPassword() {
0497: return this .password;
0498: }
0499:
0500: public void setPassword(String password) {
0501: this .password = password;
0502: }
0503:
0504: public String getServerCommand() {
0505: return this .serverCommand;
0506: }
0507:
0508: public void setServerCommand(String command) {
0509: this .serverCommand = command;
0510: }
0511:
0512: public int getConnectionMethod() {
0513: return this .connMethod;
0514: }
0515:
0516: public void setConnectionMethod(int method) {
0517: this .connMethod = method;
0518: }
0519:
0520: public String getRshProcess() {
0521: return this .rshProcess;
0522: }
0523:
0524: public void setRshProcess(String rshProcess) {
0525: this .rshProcess = rshProcess;
0526: }
0527:
0528: public int getGzipStreamLevel() {
0529: return this .gzipStreamLevel;
0530: }
0531:
0532: public void setGzipStreamLevel(int level) {
0533: this .gzipStreamLevel = level;
0534: }
0535:
0536: public CVSEntry getDirEntry() {
0537: return this .dirEntry;
0538: }
0539:
0540: public void setDirEntry(CVSEntry dirEntry) {
0541: this .dirEntry = dirEntry;
0542: }
0543:
0544: /**
0545: * Returns the request's local directory, which represents
0546: * the project's local directory.
0547: *
0548: * @return The request's local directory.
0549: */
0550: public String getLocalDirectory() {
0551: return this .localDirectory;
0552: }
0553:
0554: /**
0555: * Sets the request's local directory.
0556: *
0557: * @param localDirectory The new local directory for the request.
0558: */
0559: public void setLocalDirectory(String localDirectory) {
0560: this .localDirectory = localDirectory;
0561: }
0562:
0563: /**
0564: * Returns the request's entry's local file.
0565: *
0566: * @return The request's entry's local file.
0567: */
0568: public File getLocalFile(CVSEntry entry) {
0569: File result = new File(this .localDirectory + "/"
0570: + entry.getFullName());
0571:
0572: if (false)
0573: CVSTracer.traceIf(true, "CVSRequest.getLocalFile: entry '"
0574: + entry.getFullName() + "' localFile '"
0575: + result.getPath() + "'");
0576:
0577: return result;
0578: }
0579:
0580: /**
0581: * Returns the request's root directory, which represents
0582: * the project's CVS root directory on the server.
0583: *
0584: * @return The request's root directory.
0585: */
0586: public String getRootDirectory() {
0587: return this .rootDirectory;
0588: }
0589:
0590: /**
0591: * Sets the request's root directory.
0592: *
0593: * @param rootDirectory The new root directory for the request.
0594: */
0595: public void setRootDirectory(String rootDirectory) {
0596: this .rootDirectory = rootDirectory;
0597: }
0598:
0599: /**
0600: * Returns the request's repository, which represents
0601: * the project's CVS module on the server.
0602: *
0603: * @return The request's repository.
0604: */
0605: public String getRepository() {
0606: return this .repository;
0607: }
0608:
0609: /**
0610: * Sets the request's repository (or module name).
0611: *
0612: * @param repository The request's repository.
0613: */
0614: public void setRepository(String repository) {
0615: this .repository = repository;
0616: }
0617:
0618: /**
0619: * Returns the request's ROOT repository. This is the
0620: * full repository path to the root entry's directory.
0621: * This should match rootEntry.getRepository().
0622: *
0623: * @return The request's ROOT repository.
0624: */
0625: public String getRootRepository() {
0626: return this .rootRepository;
0627: }
0628:
0629: /**
0630: * Sets the request's ROOT repository.
0631: *
0632: * @param repository The request's ROOT repository.
0633: */
0634: public void setRootRepository(String repository) {
0635: this .rootRepository = repository;
0636: }
0637:
0638: /**
0639: * Returns the request's response handler.
0640: *
0641: * @return The request's response handler.
0642: */
0643: public CVSResponseHandler getResponseHandler() {
0644: return this .responseHandler;
0645: }
0646:
0647: /**
0648: * Sets the request's response handler.
0649: *
0650: * @param repository The request's response handler.
0651: */
0652: public void setResponseHandler(CVSResponseHandler responseHandler) {
0653: this .responseHandler = responseHandler;
0654: }
0655:
0656: /**
0657: * Returns the request's entry list as a vector.
0658: *
0659: * @return The request's entry list in a CVSEntryVector.
0660: */
0661: public CVSEntryVector getEntries() {
0662: return this .entries;
0663: }
0664:
0665: /**
0666: * Sets the request's entry list.
0667: *
0668: * @param entries The new list of entries for this request.
0669: */
0670: public void setEntries(CVSEntryVector entries) {
0671: this .entries = entries;
0672: }
0673:
0674: /**
0675: * Returns the request's entry selector.
0676: *
0677: * @return The request's entry selector.
0678: */
0679: public int getEntrySelector() {
0680: return this .entrySelector;
0681: }
0682:
0683: /**
0684: * Returns the request's argument list as a vector.
0685: *
0686: * @return The request's argument list.
0687: */
0688: public CVSArgumentVector getArguments() {
0689: return this .arguments;
0690: }
0691:
0692: /**
0693: * Sets the request's argument list.
0694: *
0695: * @param arguments The new list of argument for this request.
0696: */
0697: public void setArguments(CVSArgumentVector arguments) {
0698: this .arguments = arguments;
0699: }
0700:
0701: /**
0702: * Appends an argument list to the request's argument list.
0703: *
0704: * @param arguments The list of arguments to append.
0705: */
0706: public void appendArguments(CVSArgumentVector newArgs) {
0707: if (this .arguments == null) {
0708: this .arguments = new CVSArgumentVector();
0709: }
0710:
0711: for (int i = 0; newArgs != null && i < newArgs.size(); ++i) {
0712: this .arguments.appendArgument(newArgs.argumentAt(i));
0713: }
0714: }
0715:
0716: /**
0717: * Returns the request's global argument list as a vector.
0718: *
0719: * @return The request's argument list.
0720: */
0721: public CVSArgumentVector getGlobalArguments() {
0722: return this .globalargs;
0723: }
0724:
0725: /**
0726: * Sets the request's global argument list.
0727: *
0728: * @param arguments The new list of argument for this request.
0729: */
0730: public void setGlobalArguments(CVSArgumentVector arguments) {
0731: this .globalargs = arguments;
0732: }
0733:
0734: /**
0735: * Appends an argument list to the request's global argument list.
0736: *
0737: * @param arguments The list of arguments to append.
0738: */
0739: public void appendGlobalArguments(CVSArgumentVector newArgs) {
0740: if (this .globalargs == null) {
0741: this .globalargs = new CVSArgumentVector();
0742: }
0743:
0744: for (int i = 0; i < newArgs.size(); ++i) {
0745: this .globalargs.appendArgument(newArgs.argumentAt(i));
0746: }
0747: }
0748:
0749: /**
0750: * Returns the request's command name.
0751: *
0752: * @return The request's command name.
0753: */
0754: public String getCommand() {
0755: return this .command;
0756: }
0757:
0758: /**
0759: * Sets the request's command.
0760: *
0761: * @param command The new command for this request.
0762: */
0763: public void setCommand(String command) {
0764: this .command = command;
0765: }
0766:
0767: /**
0768: * Returns the request's user set variables.
0769: *
0770: * @return The request's user set variables.
0771: */
0772: public String[] getSetVariables() {
0773: return this .setVars;
0774: }
0775:
0776: /**
0777: * Sets the request's user set variables.
0778: *
0779: * @param vars The new user set variables.
0780: */
0781: public void setSetVariables(String[] vars) {
0782: this .setVars = vars;
0783: }
0784:
0785: /**
0786: * Returns the request's 'Sticky' settings.
0787: *
0788: * @return The request's 'Sticky' settings Hashtable.
0789: */
0790: public Hashtable getStickys() {
0791: return this .stickys;
0792: }
0793:
0794: /**
0795: * Sets the request's 'Sticky' settings.
0796: *
0797: * @param stickys The new Hashtable of this request's 'Sticky' settings.
0798: */
0799: public void setStickys(Hashtable stickys) {
0800: this .stickys = stickys;
0801: }
0802:
0803: /**
0804: * Returns the request's 'Static-directory' settings.
0805: *
0806: * @return The request's 'Static-directory' settings Hashtable.
0807: */
0808: public Hashtable getStatics() {
0809: return this .statics;
0810: }
0811:
0812: /**
0813: * Sets the request's 'Static-directory' settings.
0814: *
0815: * @param statics The new Hashtable of 'Static-directory' settings.
0816: */
0817: public void setStatics(Hashtable statics) {
0818: this .statics = statics;
0819: }
0820:
0821: /**
0822: * Returns the request's 'Checkin-prog' setting.
0823: *
0824: * @return The request's 'Checkin-prog' program name.
0825: */
0826: public String getCheckInProgram() {
0827: return this .checkInProg;
0828: }
0829:
0830: /**
0831: * Sets the request's 'Checkin-prog' setting.
0832: * This does <em>not</em> create or delete the 'Checkin.prog'
0833: * administration file. This must be done by the request user.
0834: *
0835: * @param program The new checkin-program name.
0836: */
0837: public void setCheckInProgram(String program) {
0838: this .checkInProg = program;
0839: }
0840:
0841: /**
0842: * Returns the request's 'Update-prog' setting.
0843: *
0844: * @return The request's 'Update-prog' program name.
0845: */
0846: public String getUpdateProgram() {
0847: return this .updateProg;
0848: }
0849:
0850: /**
0851: * Sets the request's 'Update-prog' setting.
0852: * This does <em>not</em> create or delete the 'Update.prog'
0853: * administration file. This must be done by the request user.
0854: *
0855: * @param program The new update-program name.
0856: */
0857: public void setUpdateProgram(String program) {
0858: this .updateProg = program;
0859: }
0860:
0861: public boolean isRedirected() {
0862: return (this .redirectOutput && this .redirectWriter != null);
0863: }
0864:
0865: public void redirectLine(String line) {
0866: if (this .redirectOutput && this .redirectWriter != null) {
0867: this .redirectWriter.println(line);
0868: }
0869: }
0870:
0871: public void setRedirectWriter(PrintWriter writer) {
0872: this .redirectWriter = writer;
0873: this .redirectOutput = (writer != null);
0874: }
0875:
0876: public void endRedirection() {
0877: if (this .redirectWriter != null) {
0878: this .redirectWriter.flush();
0879: this .redirectWriter.close();
0880:
0881: this .redirectWriter = null;
0882: this .redirectOutput = false;
0883: }
0884: }
0885:
0886: static public int parseEntriesSelector(char selectCh) {
0887: int result = CVSRequest.ES_SEL;
0888:
0889: switch (selectCh) {
0890: case 'N':
0891: result = CVSRequest.ES_NONE;
0892: break;
0893: case 'A':
0894: result = CVSRequest.ES_ALL;
0895: break;
0896: case 'a':
0897: result = CVSRequest.ES_SEL;
0898: break;
0899: case 'e':
0900: result = CVSRequest.ES_SELALL;
0901: break;
0902: case 'M':
0903: result = CVSRequest.ES_ALLMOD;
0904: break;
0905: case 'm':
0906: result = CVSRequest.ES_SELMOD;
0907: break;
0908: case 'L':
0909: result = CVSRequest.ES_ALLLOST;
0910: break;
0911: case 'l':
0912: result = CVSRequest.ES_SELLOST;
0913: break;
0914: case 'U':
0915: result = CVSRequest.ES_ALLUNC;
0916: break;
0917: case 'u':
0918: result = CVSRequest.ES_SELUNC;
0919: break;
0920: case 'G':
0921: result = CVSRequest.ES_USER;
0922: break;
0923: case 'g':
0924: result = CVSRequest.ES_NEW;
0925: break;
0926: case 'p':
0927: result = CVSRequest.ES_POPUP;
0928: break;
0929: default:
0930: result = CVSRequest.ES_SEL;
0931: CVSLog.logMsg("CVSRequest.parseEntriesSelector: '"
0932: + "ERROR bad entries selector '" + selectCh + "'");
0933: break;
0934: }
0935:
0936: return result;
0937: }
0938:
0939: /**
0940: * Process a user provided, or command spec based, argument string.
0941: * The syntax is '[global options] command options'.
0942: *
0943: * @param argStr The argument string to be parsed.
0944: */
0945:
0946: public void parseArgumentString(String argStr) {
0947: // Check for global options...
0948: if (argStr.startsWith("[")) {
0949: int bktidx = argStr.indexOf("]");
0950: if (bktidx > 0) {
0951: String gArgStr = argStr.substring(1, bktidx).trim();
0952: argStr = argStr.substring(bktidx + 1).trim();
0953: if (gArgStr.length() > 0) {
0954: CVSArgumentVector gArgs = CVSArgumentVector
0955: .parseArgumentString(gArgStr);
0956:
0957: if (gArgs != null && gArgs.size() > 0) {
0958: if (this .globalargs == null)
0959: this .globalargs = gArgs;
0960: else
0961: this .globalargs.appendArguments(gArgs);
0962: }
0963: }
0964: }
0965: }
0966:
0967: CVSArgumentVector args = CVSArgumentVector
0968: .parseArgumentString(argStr);
0969:
0970: if (args != null && args.size() > 0) {
0971: if (this .arguments == null)
0972: this .arguments = args;
0973: else
0974: this .arguments.appendArguments(args);
0975: }
0976: }
0977:
0978: /**
0979: * Attempts to parse a CVS request specification string. If
0980: * the parse succeeds, this request object will be updated
0981: * to reflect the request specification, making it ready to
0982: * be handed to a CVSClient for processing.
0983: *
0984: * The string is of the format:
0985: * <pre>
0986: * :command:select:request:response:arguments
0987: * Where:
0988: * command - is a valid cvs command name (e.g., 'update', 'co', 'diff')
0989: * select - specifies which entries to apply command to
0990: * request - is a valid cvs request specification
0991: * reponse - is a valid cvs reponse handling specification
0992: * arguments - is the remainder of the string taken as command arguments
0993: * Refer to the <a href="CVSRequestSpec.html">CVSRequest Specification</a> for details.
0994: *
0995: * @param specification The CVSRequest Specification string to parse.
0996: * @return True if the parse succeeded, false if it failed.
0997: */
0998: public boolean parseControlString(String specification) {
0999: int i, tokenCount;
1000: boolean result = true;
1001: String commandStr = null;
1002: String selectorStr = null;
1003: String requestStr = null;
1004: String responseStr = null;
1005: String argumentStr = null;
1006:
1007: StringTokenizer toker = new StringTokenizer(specification, ":");
1008:
1009: tokenCount = toker.countTokens();
1010:
1011: if (tokenCount >= 4) {
1012: try {
1013: commandStr = toker.nextToken();
1014: selectorStr = toker.nextToken();
1015: requestStr = toker.nextToken();
1016: responseStr = toker.nextToken();
1017:
1018: // Get the remainder of the string...
1019: argumentStr = toker.nextToken("");
1020: // Drop the colon left on the front by toker...
1021: if (argumentStr != null) {
1022: argumentStr = argumentStr.substring(1);
1023: }
1024: } catch (NoSuchElementException ex) {
1025: // UNDONE - report except for missing argumentStr.
1026: result = false;
1027: }
1028:
1029: if (result) {
1030: this .command = commandStr;
1031:
1032: // Process the Entry Selector
1033: for (i = 0; i < selectorStr.length(); ++i) {
1034: char selectCh = selectorStr.charAt(i);
1035: this .entrySelector = CVSRequest
1036: .parseEntriesSelector(selectCh);
1037: }
1038:
1039: // Process the REQUEST Flags
1040: for (i = 0; requestStr != null
1041: && i < requestStr.length(); ++i) {
1042: char cmdChar = requestStr.charAt(i);
1043: switch (cmdChar) {
1044: case 'D':
1045: this .sendRootDirectory = false;
1046: break;
1047: case 'E':
1048: this .sendEntries = true;
1049: break;
1050: case 'S':
1051: this .sendEmptyMods = true;
1052: break;
1053: case 'U':
1054: this .sendModifieds = true;
1055: break;
1056: case 'A':
1057: this .sendArguments = true;
1058: break;
1059: case 'F':
1060: this .sendEntryFiles = true;
1061: break;
1062: case 'M':
1063: this .sendModule = true;
1064: break;
1065: case 'N':
1066: this .includeNotifies = false;
1067: break;
1068: case 'G':
1069: this .guaranteeMsg = true;
1070: break;
1071: case 'P':
1072: this .queueResponse = false;
1073: break;
1074: case 'R':
1075: this .redirectOutput = true;
1076: break;
1077: case 'V':
1078: this .verificationOnly = true;
1079: break;
1080: case 'X':
1081: this .execInCurDir = true;
1082: break;
1083: case 'O':
1084: this .traceRequest = true;
1085: break;
1086: case 'I':
1087: this .traceResponse = true;
1088: break;
1089: case 'T':
1090: this .traceTCPData = true;
1091: break;
1092: default:
1093: CVSLog.logMsg("While parsing CVSRequest '"
1094: + specification
1095: + "', found invalid request flag '"
1096: + cmdChar + "'");
1097: break;
1098: }
1099: }
1100:
1101: // Process the REPONSE Flags
1102: for (i = 0; responseStr != null
1103: && i < responseStr.length(); ++i) {
1104: char cmdChar = responseStr.charAt(i);
1105: switch (cmdChar) {
1106: case 'c':
1107: this .handleCopyFile = true;
1108: break;
1109: case 'd':
1110: this .displayReponse = true;
1111: break;
1112: case 'e':
1113: this .handleEntries = true;
1114: break;
1115: case 'f':
1116: this .handleFlags = true;
1117: break;
1118: case 'i':
1119: this .ignoreResult = true;
1120: break;
1121: case 'm':
1122: this .handleMerged = true;
1123: break;
1124: case 'o':
1125: this .allowOverWrites = true;
1126: break;
1127: case 'u':
1128: this .handleUpdated = true;
1129: break;
1130: case 'k':
1131: this .saveTempFiles = true;
1132: break;
1133: case 't':
1134: this .traceProcessing = true;
1135: break;
1136: default:
1137: CVSLog.logMsg("While parsing CVSRequest '"
1138: + specification
1139: + "', found invalid response flag '"
1140: + cmdChar + "'");
1141: break;
1142: }
1143: }
1144:
1145: // Process the ARGUMENTS if there are any...
1146: if (argumentStr != null) {
1147: this .parseArgumentString(argumentStr);
1148: }
1149: }
1150: } else {
1151: result = false;
1152: }
1153:
1154: return result;
1155: }
1156:
1157: /**
1158: * Returns the reason for the last verification failure.
1159: *
1160: * @return The reason for the last verification failure.
1161: * @see CVSRequest#verifyRequest
1162: * @see CVSRequest#setVerifyFailReason
1163: */
1164: public String getVerifyFailReason() {
1165: return this .vfReason;
1166: }
1167:
1168: /**
1169: * Sets the reason for the current verification failure.
1170: *
1171: * @param reason The reason for the current verification failure.
1172: * @see CVSRequest#verifyRequest
1173: * @see CVSRequest#getVerifyFailReason
1174: */
1175: public void setVerifyFailReason(String reason) {
1176: this .vfReason = reason;
1177: }
1178:
1179: /**
1180: * Verify the current request. This determines if the request
1181: * has enough information to be handed to a CVSClient for
1182: * processing. It also makes some sanity checks.
1183: *
1184: * @return True of the request is valid, false if not.
1185: * @see CVSRequest#verifyRequest
1186: * @see CVSRequest#getVerifyFailReason
1187: */
1188: public boolean verifyRequest() {
1189: if (this .hostName == null) {
1190: this .setVerifyFailReason("hostname is null");
1191: return false;
1192: }
1193:
1194: if (this .repository == null) {
1195: this .setVerifyFailReason("repository name is null");
1196: return false;
1197: }
1198:
1199: if (this .rootDirectory == null) {
1200: this .setVerifyFailReason("root directory is null");
1201: return false;
1202: }
1203:
1204: if (this .localDirectory == null
1205: && (this .sendModifieds || this .handleMerged
1206: || this .handleUpdated || this .handleCopyFile)) {
1207: this .setVerifyFailReason("local directory is null");
1208: return false;
1209: }
1210:
1211: if (this .entries == null) {
1212: if (this .sendEntries || this .sendEntryFiles) {
1213: this .setVerifyFailReason("entries list is null");
1214: return false;
1215: }
1216: }
1217: /*
1218: ************************** REVIEW
1219: if ( this.sendEntries && this.sendSpecialMods )
1220: {
1221: this.setVerifyFailReason(
1222: "'send entries' (E or U) and " +
1223: "'send special mods' (N) " +
1224: "are mutually exclusive." );
1225: return false;
1226: }
1227: **************************
1228: */
1229: if (this .sendArguments && this .arguments == null) {
1230: this .setVerifyFailReason("arguments list is null.");
1231: return false;
1232: }
1233:
1234: if (this .entrySelector < CVSRequest.ES_FIRST
1235: || this .entrySelector > CVSRequest.ES_LAST) {
1236: this .setVerifyFailReason("invalid entry selector");
1237: return false;
1238: }
1239:
1240: if (this .sendEntryFiles && this .sendModule) {
1241: this
1242: .setVerifyFailReason("can not send both 'files...' and 'module'");
1243: return false;
1244: }
1245:
1246: /*
1247: *** UNDONE
1248: if ( !this.sendModule
1249: && !this.sendEntryFiles
1250: && !this.command.equals( "checkout" )
1251: && !this.command.equals( "admin" )
1252: && !this.command.equals( "
1253:
1254: this.guaranteeMsg = false;
1255:
1256: this.displayReponse = false;
1257: this.handleEntries = false;
1258: this.handleFlags = false;
1259: ***
1260: */
1261:
1262: this .setVerifyFailReason("request is valid");
1263: return true;
1264: }
1265:
1266: /**
1267: * Returns a string representation of this request.
1268: *
1269: * @return String representing request.
1270: */
1271: public String toString() {
1272: return "CVSRequest: command=" + this.command;
1273: }
1274:
1275: }
|