0001: // CvsFrame.java
0002: // $Id: CvsFrame.java,v 1.31 2007/02/09 13:44:47 ylafon Exp $
0003: // (c) COPYRIGHT MIT and INRIA, 1996.
0004: // Please first read the full copyright statement in file COPYRIGHT.html
0005:
0006: package org.w3c.jigedit.cvs;
0007:
0008: import java.io.File;
0009: import java.io.InputStream;
0010: import java.io.IOException;
0011: import java.io.StringBufferInputStream;
0012:
0013: import java.util.Enumeration;
0014: import java.util.Hashtable;
0015: import java.util.Vector;
0016:
0017: import java.net.URL;
0018:
0019: import org.w3c.jigsaw.frames.HTTPFrame;
0020: import org.w3c.jigsaw.frames.PostableFrame;
0021:
0022: import org.w3c.cvs.CVS;
0023: import org.w3c.cvs.CvsDirectory;
0024: import org.w3c.cvs.CvsException;
0025:
0026: import org.w3c.www.http.HTTP;
0027: import org.w3c.www.http.HttpCacheControl;
0028: import org.w3c.www.http.HttpFactory;
0029: import org.w3c.www.http.HttpMessage;
0030: import org.w3c.www.http.HttpReplyMessage;
0031: import org.w3c.www.http.HttpTokenList;
0032:
0033: import org.w3c.jigsaw.http.HTTPException;
0034: import org.w3c.jigsaw.http.Reply;
0035: import org.w3c.jigsaw.http.Request;
0036: import org.w3c.jigsaw.http.httpd;
0037:
0038: import org.w3c.jigsaw.auth.AuthFilter;
0039:
0040: import org.w3c.tools.resources.DirectoryResource;
0041: import org.w3c.tools.resources.FileResource;
0042: import org.w3c.tools.resources.FramedResource;
0043: import org.w3c.tools.resources.InvalidResourceException;
0044: import org.w3c.tools.resources.LookupResult;
0045: import org.w3c.tools.resources.LookupState;
0046: import org.w3c.tools.resources.MultipleLockException;
0047: import org.w3c.tools.resources.ProtocolException;
0048: import org.w3c.tools.resources.Resource;
0049: import org.w3c.tools.resources.ResourceFrame;
0050: import org.w3c.tools.resources.ResourceReference;
0051: import org.w3c.tools.resources.ServerInterface;
0052:
0053: import org.w3c.jigsaw.forms.URLDecoder;
0054: import org.w3c.jigsaw.forms.URLDecoderException;
0055:
0056: import org.w3c.jigsaw.html.HtmlGenerator;
0057: import org.w3c.jigsaw.html.HtmlLink;
0058:
0059: import org.w3c.tools.sorter.Sorter;
0060:
0061: import org.w3c.util.ObservableProperties;
0062:
0063: public class CvsFrame extends PostableFrame {
0064:
0065: protected static HttpCacheControl CACHE_CONTROL_NOCACHE = null;
0066: protected static HttpTokenList PRAGMA_NOCACHE = null;
0067:
0068: static {
0069: // Pre-compute the no cache directives:
0070: CACHE_CONTROL_NOCACHE = HttpFactory.makeCacheControl();
0071: CACHE_CONTROL_NOCACHE.setNoCache();
0072: // Pre-compute the no cache directives:
0073: String nocache[] = { "no-cache" };
0074: PRAGMA_NOCACHE = HttpFactory.makeStringList(nocache);
0075: }
0076:
0077: /**
0078: * Have we already computed our CVS environment ?
0079: */
0080: private static boolean inited = false;
0081:
0082: private CvsDirectory cvs = null;
0083: private CvsHandlerInterface handler = null;
0084: private Hashtable entries = null; //<name, CvsEntryResource>
0085:
0086: private static char alphabet[] = { '0', '1', '2', '3', '4', '5',
0087: '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0088: 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
0089: 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
0090: 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
0091: 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
0092:
0093: protected static void addStyle(HtmlGenerator g) {
0094: g.addStyle("CAPTION {color: red; font-weight: bold; "
0095: + "padding: 3pt; }\n");
0096: g.addStyle(".warning { color: red; font-weight: bold; }\n");
0097: g.addStyle("P.error { color: black; font-weight: bold; "
0098: + "font-size: large; }\n");
0099: g.addStyle("A {color: darkblue; font-weight: bold; "
0100: + " text-decoration: none; }\n");
0101: g
0102: .addStyle("A.alphalink {color: darkblue; text-decoration: none; "
0103: + "font: bold 10pt Verdana, sans-serif; }\n");
0104: g.addStyle("A.script {color: darkblue; text-decoration: none; "
0105: + "font: bold 8pt Verdana, sans-serif; }\n");
0106: g.addStyle("H1.center {color:white;font-weight:bold;"
0107: + "text-align:center; }\n");
0108: g
0109: .addStyle("DIV.box { margin: 2.0%; margin-top: 1.0%; padding: 1.0%;"
0110: + " border: thin solid black; width: 100.0%; }\n");
0111: g
0112: .addStyle("DIV.boxcenter { margin: 2.0%; margin-top: 1.0%; "
0113: + " padding: 1.0%; border: thin solid black; width: 100.0%; "
0114: + " text-align: center; } \n");
0115: g.addStyle("DIV.error{ margin-left: 10.0%; margin-top: 1.0%; "
0116: + "padding: 1.0%; width: 80.0%; }\n");
0117: g
0118: .addStyle(".title { color: red; font-weight: bold; padding: 3pt; "
0119: + " font-size: large; text-align: center; }\n");
0120: g.addStyle(".statusok { color: gray; }\n");
0121: g.addStyle(".status { color: red; font-weight: bold}\n");
0122: g.addStyle(".titleblack { color: black; font-weight: bold;"
0123: + " padding: 3pt; font-size: large; "
0124: + "text-align: center; }\n");
0125: }
0126:
0127: /**
0128: * Get an HtmlGenerator with some style defined:<br>
0129: * <strong>tags with style</strong>
0130: * <ul>
0131: * <li> BODY
0132: * <li> CAPTION
0133: * <li> P.error
0134: * <li> A
0135: * <li> A.alphalink
0136: * <li> H1.center
0137: * </ul>
0138: * <strong>Some DIV</strong>
0139: * <ul>
0140: * <li> DIV.box
0141: * <li> DIV.boxcenter
0142: * <li> DIV.error
0143: * </ul>
0144: * <strong>Some SPAN</strong>
0145: * <ul>
0146: * <li> .warning
0147: * <li> .title
0148: * <li> .status
0149: * <li> .statusok
0150: * <li> .titleblack
0151: * </ul>
0152: * @param title The document title.
0153: * @return a HtmlGenerator instance.
0154: */
0155: public static HtmlGenerator getHtmlGenerator(String title) {
0156: HtmlGenerator g = new HtmlGenerator(title);
0157: g.addStyle("BODY {color: black; background: white; "
0158: + "font-family: serif; margin-top: 35px }\n");
0159: addStyle(g);
0160: return g;
0161: }
0162:
0163: /**
0164: * Like getHtmlGenerator(String), and add the frame style sheet.
0165: * @param title The document title.
0166: * @return a HtmlGenerator instance.
0167: */
0168: public static HtmlGenerator getHtmlGenerator(CvsFrame cvsframe,
0169: String title) {
0170: HtmlGenerator g = new HtmlGenerator(title);
0171: cvsframe.addStyleSheet(g);
0172: addStyle(g);
0173: return g;
0174: }
0175:
0176: /**
0177: * Emit an HTML error message.
0178: * @param request The request that trigered the error.
0179: * @param msg The error message.
0180: * @param ex The CvsException that happened while processing the request.
0181: * @return An HTTP reply.
0182: */
0183: protected static Reply error(Request request, String msg,
0184: CvsException ex) {
0185: return error(request, msg, ex.getMessage());
0186: }
0187:
0188: /**
0189: * Emit an HTML error message.
0190: * @param request The request that trigered the error.
0191: * @param msg The error message.
0192: * @return An HTTP reply.
0193: */
0194: protected static Reply error(Request request, String msg,
0195: String details) {
0196: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
0197: HtmlGenerator g = getHtmlGenerator(msg);
0198: g.append("<center>");
0199: g
0200: .append("[ <A HREF=\"./CVS\">Back</A> ]<hr noshade width=\"80%\">");
0201: g.append("</center>");
0202: g.append("<div class=\"error\"> <center><p class=\"error\">",
0203: msg, "</center><p>\n");
0204: g.append("Details : <p><em>", details, "</em><p></div>\n");
0205: g.append("<hr noshade width=\"80%\">");
0206: error.setStream(g);
0207: return error;
0208: }
0209:
0210: /**
0211: * Emit an HTML error message.
0212: * @param cvsframe The CvsFrame sending this error.
0213: * @param request The request that trigered the error.
0214: * @param msg The error message.
0215: * @param ex The CvsException that happened while processing the request.
0216: * @return An HTTP reply.
0217: */
0218: protected static Reply error(CvsFrame cvsframe, Request request,
0219: String msg, CvsException ex) {
0220: return error(cvsframe, request, msg, ex.getMessage());
0221: }
0222:
0223: /**
0224: * Emit an HTML error message.
0225: * @param cvsframe The CvsFrame sending this error
0226: * @param request The request that trigered the error.
0227: * @param msg The error message.
0228: * @return An HTTP reply.
0229: */
0230: protected static Reply error(CvsFrame cvsframe, Request request,
0231: String msg, String details) {
0232: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
0233: HtmlGenerator g = getHtmlGenerator(cvsframe, msg);
0234: g.append("<center>");
0235: g
0236: .append("[ <A HREF=\"./CVS\">Back</A> ]<hr noshade width=\"80%\">");
0237: g.append("</center>");
0238: g.append("<div class=\"error\"> <center><p class=\"error\">",
0239: msg, "</center><p>\n");
0240: g.append("Details : <p><em>", details, "</em><p></div>\n");
0241: g.append("<hr noshade width=\"80%\">");
0242: error.setStream(g);
0243: return error;
0244: }
0245:
0246: /**
0247: * Get a suitable FramedResource to display the given cvs'ed file.
0248: * @param name The name of the file.
0249: * @return A CvsEntryResource, or <strong>null</strong> if none was
0250: * found.
0251: */
0252: protected FramedResource getResourceFor(String name) {
0253: CvsEntryResource entry = null;
0254: if (entries == null) {
0255: entries = new Hashtable(3);
0256: entry = new CvsEntryResource(getFrameReference(), name);
0257: entries.put(name, entry);
0258: } else {
0259: entry = (CvsEntryResource) entries.get(name);
0260: if (entry == null) {
0261: entry = new CvsEntryResource(getFrameReference(), name);
0262: entries.put(name, entry);
0263: }
0264: }
0265: return entry;
0266: }
0267:
0268: private CvsDirectory getManager(File directory) throws CvsException {
0269: return CvsModule.getCvsManager(directory, getContext(),
0270: getServer().getProperties());
0271: }
0272:
0273: /**
0274: * Get the CVS manager associated with this resource, or create it.
0275: */
0276: protected synchronized CvsDirectory getCvsManager() {
0277: if (cvs == null) {
0278: ResourceReference rrp = resource.getParent();
0279: if (rrp != null) {
0280: try {
0281: Resource parent = rrp.lock();
0282: if (!(parent instanceof DirectoryResource)) {
0283: getServer().errlog(resource,
0284: "not a child of a DirectoryResource");
0285: throw new RuntimeException(
0286: "The server is misconfigured.");
0287: }
0288: // CVS will only work within a (filesystem)
0289: // directory resource
0290: File d = ((DirectoryResource) parent)
0291: .getDirectory();
0292: try {
0293: cvs = getManager(d);
0294: } catch (CvsException ex) {
0295: String msg = ("unable to create a cvs manager for \""
0296: + d.getAbsolutePath() + "\".");
0297: getServer().errlog(this , msg);
0298: throw new RuntimeException("CVS failed.");
0299: }
0300: handler = new CvsDirectoryHandler(cvs);
0301: } catch (InvalidResourceException ex) {
0302: getServer().errlog(resource, "Invalid parent");
0303: throw new RuntimeException(
0304: "The server is misconfigured.");
0305: } finally {
0306: rrp.unlock();
0307: }
0308: }
0309: }
0310: return cvs;
0311: }
0312:
0313: protected boolean isIndexed(String name) {
0314: ResourceReference rrp = resource.getParent();
0315: if (rrp != null) {
0316: try {
0317: Resource parent = rrp.lock();
0318: if (!(parent instanceof DirectoryResource)) {
0319: getServer().errlog(resource,
0320: "not a child of a DirectoryResource");
0321: throw new RuntimeException(
0322: "The server is misconfigured.");
0323: }
0324: return (((DirectoryResource) parent).lookup(name) != null);
0325: } catch (InvalidResourceException ex) {
0326: getServer().errlog(resource, "Invalid parent");
0327: throw new RuntimeException(
0328: "The server is misconfigured.");
0329: } finally {
0330: rrp.unlock();
0331: }
0332: } else {
0333: getServer().errlog(resource, "No parent!");
0334: throw new RuntimeException("The server is misconfigured.");
0335: }
0336: }
0337:
0338: /**
0339: * Perform the given action on the underlying directory as a whole.
0340: * @param action The action to perform.
0341: * @param request The request that triggered the action.
0342: * @param data The decoded form data.
0343: * @return A suitable HTTP reply.
0344: * @exception ProtocolException if a protocol error occurs
0345: */
0346: protected Reply performDirectoryAction(String action,
0347: Request request, org.w3c.jigsaw.forms.URLDecoder data)
0348: throws ProtocolException {
0349: if (action.equals("refresh")) {
0350: // Following command will cause a refresh if needed:
0351: try {
0352: getCvsManager().listFiles();
0353: } catch (CvsException ex) {
0354: return error(this , request,
0355: "Error while refreshing directory", ex);
0356: }
0357: } else if (action.equals("commit")) {
0358: // Commit the whole directory:
0359: try {
0360: String comment = data.getValue("comment");
0361: String u = (String) request
0362: .getState(AuthFilter.STATE_AUTHUSER);
0363: String env[] = { "USER=" + u, "LOGNAME=" + u };
0364: comment = ((comment == null) ? "Changed through Jigsaw."
0365: : comment);
0366: comment = ((u != null) ? ("(" + u + ") " + comment)
0367: : comment);
0368: getCvsManager().commit(comment, env);
0369: } catch (CvsException ex) {
0370: return error(this , request,
0371: "Error while commiting directory", ex);
0372: }
0373: } else if (action.equals("update")) {
0374: // Update the whole directory:
0375: try {
0376: getCvsManager().update();
0377: } catch (CvsException ex) {
0378: return error(this , request,
0379: "Error while updating directory", ex);
0380: }
0381: } else {
0382: // Unknown directory command:
0383: return error(this , request, "Command not allowed",
0384: "This command is not allowed on directories.");
0385: }
0386: return get(request);
0387: }
0388:
0389: /**
0390: * Register the resource and add CvsProperties in httpd.
0391: * @param resource The resource to register.
0392: */
0393: public void registerResource(FramedResource resource) {
0394: super .registerOtherResource(resource);
0395: if (!inited) {
0396: synchronized (this .getClass()) {
0397: httpd s = (httpd) getServer();
0398: if (s != null) {
0399: // Register the CVS property sheet if not done yet:
0400: ObservableProperties props = s.getProperties();
0401: s.registerPropertySet(new CvsProp("cvs", s));
0402: inited = true;
0403: }
0404: }
0405: }
0406: }
0407:
0408: /**
0409: * Lookup method for the CVS manager.
0410: * Lookup for a cvs entry object having the given name, if found, wrap it
0411: * into a CvsEntryResource object and return it.
0412: * @param ls The current lookup state.
0413: * @param lr The (under construction) lookup result.
0414: * @exception ProtocolException if a protocol error occurs
0415: */
0416: protected boolean lookupOther(LookupState ls, LookupResult lr)
0417: throws ProtocolException {
0418: if (super .lookupOther(ls, lr))
0419: return true;
0420: String name = ls.getNextComponent();
0421: try {
0422: int status = getCvsManager().getDirectoryStatus(name);
0423: if (status == CVS.DIR_Q) {
0424: lr.setTarget(null);
0425: return true;
0426: } else if (status == CVS.DIR_NCO) {
0427: // Checkout directory, and relocate:
0428: getCvsManager().updateDirectory(name);
0429: Request request = (Request) ls.getRequest();
0430: if (request != null) {
0431: Reply relocate = request.makeReply(HTTP.FOUND);
0432: try {
0433: URL myloc = getURL(request);
0434: URL location = new URL(myloc, name + "/CVS");
0435: relocate.setLocation(location);
0436: lr.setReply(relocate);
0437: } catch (Exception ex) {
0438: }
0439: }
0440: lr.setTarget(null);
0441: return true;
0442: } else if (getCvsManager().status(name) != CVS.FILE_Q) {
0443: FramedResource target = getResourceFor(name);
0444: lr.setTarget(target.getResourceReference());
0445: target.lookup(ls, lr);
0446: return true;
0447: } else {
0448: lr.setTarget(null);
0449: return true;
0450: }
0451: } catch (CvsException ex) {
0452: throw new HTTPException("status failed in CVS directory.");
0453: }
0454: }
0455:
0456: /**
0457: * Dump one CVS entry into HTML.
0458: * The generated HTML is expected to insert itself in a table.
0459: * @param g The HTML generator to use.
0460: * @param name The entry to be dumped.
0461: * @exception CvsException If the CVS access failed to this entry.
0462: */
0463: private void dumpFileEntry(HtmlGenerator g, String name)
0464: throws CvsException {
0465: String eurl = resource.getURLPath() + "/" + name;
0466: int status = getCvsManager().status(name);
0467: String revision = getCvsManager().revision(name);
0468: boolean indexed = isIndexed(name);
0469:
0470: // Entry toggle:
0471: g.append("<tr><td><input type=\"checkbox\" name=\"" + name
0472: + "\" value=\"mark\">");
0473: // Dump the entry name (link only if checked out):
0474: if ((status == CVS.FILE_NCO) || (!indexed))
0475: g.append("<td align=left><b>", name, "</b>");
0476: else
0477: g.append("<td align=left><a href=\"" + name + "\">" + name
0478: + "</a>\n");
0479: // Dump the revision number
0480: if (revision == null)
0481: g.append("<td>\n");
0482: else {
0483: int index = revision.indexOf(".");
0484: if (index != -1) {
0485: g.append("<td align=left><select name=\"" + name
0486: + ".rev\">\n");
0487: String minor = revision.substring(index + 1);
0488: String major = revision.substring(0, index);
0489: int max = 0;
0490: try {
0491: max = Integer.parseInt(minor);
0492: } catch (NumberFormatException ex) {
0493: g.append("<option value=\"" + revision + "\">"
0494: + revision + "</option>\n");
0495: max = 0;
0496: }
0497: for (int i = max; i > 0; i--) {
0498: g.append("<option value=\"" + major + "." + i
0499: + "\">" + major + "." + i + "</option>\n");
0500: }
0501: g.append("</select>\n");
0502: } else {
0503: g.append("<td>\n");
0504: }
0505: }
0506: // Dump the entry status:
0507: g.append("<td>\n");
0508: if (status != CVS.FILE_OK) {
0509: g.append("<span class=\"status\">", getCvsManager()
0510: .statusToString(status), "</span>");
0511: } else {
0512: g.append("<span class=\"statusok\">", getCvsManager()
0513: .statusToString(status), "</span>");
0514: }
0515: if ((status != CVS.FILE_NCO) && (!indexed))
0516: g.append(" (not indexed)");
0517:
0518: // Emit a diff/log hyper-link only if this makes sense (entry is known)
0519: if (status != CVS.FILE_Q)
0520: g
0521: .append("<td> [ <a href=\"" + eurl
0522: + "?log\">log</a> ] \n");
0523: if (status == CVS.FILE_M)
0524: g.append("<td> [ <a href=\"" + eurl
0525: + "?diff\">diff</a> ] \n");
0526: }
0527:
0528: /**
0529: * Dump one CVS Directory entry into HTML.
0530: * The produced HTML is expected to insert itself into a table.
0531: * @param g The HTML generator to use.
0532: * @param name The name of the directory to dumped.
0533: * @exception CvsException If the CVS access failed to this entry.
0534: */
0535: private void dumpDirectoryEntry(HtmlGenerator g, String name)
0536: throws CvsException {
0537: int status = getCvsManager().getDirectoryStatus(name);
0538: String eurl = name + "/CVS";
0539:
0540: // Dump the toggle:
0541: g.append("<tr><td><input type=\"checkbox\" name=\"" + name
0542: + "\" value=\"mark\">");
0543: // Dump the entry name (and link if available):
0544: if (status == CVS.DIR_NCO)
0545: g.append("<td align=left><b>", name, "</b>");
0546: else
0547: g.append("<td align=left><a href=\"" + name + "\">" + name
0548: + "</a>\n");
0549: // Dump more links:
0550: if (status != CVS.DIR_Q) {
0551: if (status != CVS.DIR_NCO)
0552: g.append("<td align=left><a href=\"", eurl,
0553: "\">CVS</a>\n");
0554: else
0555: g.append("<td align=left>CVS [ <a href=\""
0556: + resource.getURLPath() + "/" + name
0557: + "\"> checkout</a> ] \n");
0558: } else {
0559: g.append("<td aligne=left>\n");
0560: }
0561: // dump one line for the status:
0562: g.append("<td>\n");
0563: if (status == CVS.DIR_CO) {
0564: g.append("<span class=\"statusok\">", getCvsManager()
0565: .statusToString(status), "</span>");
0566: } else {
0567: g.append("<span class=\"status\">", getCvsManager()
0568: .statusToString(status), "</span>");
0569: }
0570: }
0571:
0572: protected void refresh(Request request) throws ProtocolException {
0573: try {
0574: getCvsManager().refresh();
0575: } catch (CvsException ex) {
0576: Reply error = error(this , request,
0577: "Error while refreshing directory", ex);
0578: throw new HTTPException(error);
0579: }
0580: }
0581:
0582: /**
0583: * Dump the content of the directory as a CVS form.
0584: * The resulting form allows for trigerring actions on the various files.
0585: * @exception ProtocolException if a protocol error occurs
0586: */
0587: public Reply get(Request request) throws ProtocolException {
0588:
0589: String action = getAction(request);
0590: boolean showdirs = false;
0591:
0592: if (action.equals("refreshfiles")) {
0593: refresh(request);
0594: } else if (action.equals("refreshdirs")) {
0595: refresh(request);
0596: showdirs = true;
0597: } else if (action.equals("showdirs")) {
0598: showdirs = true;
0599: }
0600:
0601: boolean no_entries = true;
0602: HtmlGenerator g = getHtmlGenerator(this , "CVS for "
0603: + getCvsManager().getDirectory());
0604: addStyleSheet(g);
0605: g.addLink(new HtmlLink(null, "made", "jigsaw@w3.org"));
0606:
0607: String tablecolor = "white";
0608: String parentpath = null;
0609: ResourceReference rr_parent = resource.getParent();
0610: try {
0611: Resource parent = rr_parent.lock();
0612: parentpath = parent.getURLPath();
0613: } catch (InvalidResourceException ex) {
0614: getServer().errlog(resource, "Invalid parent");
0615: throw new RuntimeException("The server is misconfigured.");
0616: } finally {
0617: rr_parent.unlock();
0618: }
0619:
0620: //entries
0621: boolean nofile = true;
0622: boolean nodir = true;
0623: Vector names = null;
0624: Vector dirnames = null;
0625:
0626: //javascript
0627: g.addScript("JavaScript", "var submitOK = true;\n\n");
0628:
0629: g.addScript("function SelectAll() {\n");
0630: g.addScript(" len = document.liste.elements.length;\n");
0631: g.addScript(" var i=0; var checked; var item;\n");
0632: g
0633: .addScript(" if (document.liste.elements[i].checked == true)\n");
0634: g.addScript(" checked = false;\n");
0635: g.addScript(" else\n");
0636: g.addScript(" checked = true;\n");
0637: g.addScript(" for( i=0; i<len; i++) {\n");
0638: g
0639: .addScript(" item = document.liste.elements[i].name;\n");
0640: g
0641: .addScript(" if (item !='action' && item != 'scope')\n");
0642: g
0643: .addScript(" document.liste.elements[i].checked=checked;");
0644: g.addScript("\n }\n");
0645: g.addScript("}\n\n");
0646:
0647: g.addScript("function confirmDirAction() {\n");
0648: g.addScript(" len = document.liste.elements.length;\n");
0649: g.addScript(" var i=0; var item; var oneselected=false;\n");
0650: g.addScript(" for( i=0; i<len; i++) {\n");
0651: g
0652: .addScript(" item = document.liste.elements[i].name;\n");
0653: g
0654: .addScript(" if (item !='action' && item != 'scope'){\n");
0655: g
0656: .addScript(" if (document.liste.elements[i].checked\n");
0657: g.addScript(" == true){\n");
0658: g.addScript(" oneselected = true;\n");
0659: g.addScript(" }\n");
0660: g.addScript(" }\n");
0661: g.addScript(" }\n");
0662: g.addScript(" if (oneselected == false){\n");
0663: g.addScript(" submitOK = false;\n");
0664: g.addScript(" alert('No directory selected.');\n");
0665: g.addScript(" } else {\n");
0666: g.addScript(" submitOK = true;\n");
0667: g.addScript(" }\n");
0668: g.addScript("}\n\n");
0669:
0670: g.addScript("function confirmFileAction() {\n");
0671: g.addScript(" len = document.liste.elements.length;\n");
0672: g.addScript(" var i=0; var item; var oneselected=false;\n");
0673: g
0674: .addScript(" if (document.liste.scope[0].checked == true){\n");
0675: g.addScript(" //Marked files\n");
0676: g.addScript(" for( i=0; i<len; i++) {\n");
0677: g
0678: .addScript(" item = document.liste.elements[i].name;\n");
0679: g
0680: .addScript(" if (item !='action' && item != 'scope'){\n");
0681: g
0682: .addScript(" if (document.liste.elements[i].checked\n");
0683: g.addScript(" == true){\n");
0684: g.addScript(" oneselected = true;\n");
0685: g.addScript(" }\n");
0686: g.addScript(" }\n");
0687: g.addScript(" }\n");
0688: g.addScript(" if (oneselected == false){\n");
0689: g.addScript(" submitOK = false;\n");
0690: g.addScript(" alert('No file selected.');\n");
0691: g.addScript(" }\n");
0692: g.addScript(" } else if (document.liste.scope[1].checked\n");
0693: g.addScript(" == true){\n");
0694: g.addScript(" //Directory\n");
0695: g
0696: .addScript(" if (document.liste.action[1].checked == true\n");
0697: g.addScript(" ||\n");
0698: g
0699: .addScript(" document.liste.action[2].checked == true){\n");
0700: g.addScript(" oneselected = true;\n");
0701: g.addScript(" } else {\n");
0702: g
0703: .addScript(" alert('Command not allowed on directory');\n");
0704: g.addScript(" oneselected = false;\n");
0705: g.addScript(" }\n");
0706: g.addScript(" } else if (document.liste.scope[2].checked\n");
0707: g.addScript(" == true){\n");
0708: g.addScript(" //Matching files\n");
0709: g
0710: .addScript(" if (document.liste.regval.value == ''){\n");
0711: g
0712: .addScript(" alert('No regular expression specified.');\n");
0713: g.addScript(" oneselected = false;\n");
0714: g
0715: .addScript(" } else if (document.liste.action[3].checked "
0716: + "== true || document.liste.action[4].checked == true){\n");
0717: g
0718: .addScript(" alert('Command not allowed with regular "
0719: + "expressions');\n");
0720: g.addScript(" oneselected = false;\n");
0721: g.addScript(" } else {\n");
0722: g.addScript(" oneselected = true;\n");
0723: g.addScript(" }\n");
0724: g.addScript(" } else {\n");
0725: g.addScript(" oneselected = true;\n");
0726: g.addScript(" }\n");
0727: g.addScript(" if (oneselected == false) {\n");
0728: g.addScript(" submitOK = false;\n");
0729: g
0730: .addScript(" } else if (document.liste.action[4].checked != \n");
0731: g.addScript(" true){\n");
0732: g.addScript(" submitOK = true;\n");
0733: g
0734: .addScript(" } else if (confirm('Do you really want to remove "
0735: + "these files ?')) {\n");
0736: g.addScript(" submitOK = true;\n");
0737: g.addScript(" } else {\n");
0738: g.addScript(" submitOK = false;\n");
0739: g.addScript(" }\n");
0740: g.addScript("}\n\n");
0741:
0742: g.addScript("function accFileSub() {\n");
0743: g.addScript(" if (submitOK == false) {\n");
0744: g.addScript(" submitOK = true;\n");
0745: g.addScript(" return(false);\n");
0746: g.addScript(" } else {\n");
0747: g.addScript(" return(true);\n");
0748: g.addScript(" }\n");
0749: g.addScript("}\n");
0750:
0751: g.addScript("function accDirSub() {\n");
0752: g.addScript(" if (submitOK == false) {\n");
0753: g.addScript(" submitOK = true;\n");
0754: g.addScript(" return(false);\n");
0755: g.addScript(" } else {\n");
0756: g.addScript(" return(true);\n");
0757: g.addScript(" }\n");
0758: g.addScript("}\n");
0759:
0760: // Dump all file entries:
0761: Enumeration gen_enum = null;
0762: try {
0763: gen_enum = getCvsManager().listFiles();
0764: names = Sorter.sortStringEnumeration(gen_enum);
0765: nofile = (names.size() == 0);
0766: } catch (CvsException ex) {
0767: throw new HTTPException(error(this , request,
0768: "unable to list files", ex));
0769: }
0770:
0771: // get a vector of directory entries
0772: try {
0773: gen_enum = getCvsManager().listDirectories();
0774: dirnames = Sorter.sortStringEnumeration(gen_enum);
0775: nodir = (dirnames.size() == 0);
0776: } catch (CvsException ex) {
0777: throw new HTTPException(error(this , request,
0778: "unable to list directories", ex));
0779: }
0780:
0781: String head = " [ <a href=\"./\">Up to directory</A> ]";
0782: if (!nofile) {
0783: head += " · [ <A HREF=\"" + resource.getURLPath()
0784: + "\">Files</A> ]";
0785: if (!nodir)
0786: head += " · [ <A HREF=\""
0787: + resource.getURLPath()
0788: + "?action=showdirs\">Directories</A> ]";
0789: else
0790: head += " · [ Directories ]";
0791: } else if (!nodir) {
0792: head += " · [ Files ]";
0793: head += " · [ <A HREF=\"" + resource.getURLPath()
0794: + "?action=showdirs\">Directories</A> ]";
0795: } else {
0796: head += " · [ Files ]";
0797: head += " · [ Directories ]";
0798: }
0799: head += " · [ <A HREF=\"" + resource.getURLPath()
0800: + "?action="
0801: + (showdirs ? "refreshdirs" : "refreshfiles")
0802: + "\">Refresh</A> ]";
0803:
0804: g.append("<A NAME=\"top\"></A>");
0805: g.append("<center>", head,
0806: "<hr noshade width=\"80%\"></center>");
0807: g.append("<center><div class=\"boxcenter\">");
0808: g.append(" <a class=\"alphalink\" href=\"#" + alphabet[0]
0809: + "\">" + alphabet[0] + "</a>");
0810: for (int i = 1; i < alphabet.length; i++)
0811: g.append(" · <a class=\"alphalink\" href=\"#"
0812: + alphabet[i] + "\">" + alphabet[i] + "</a>");
0813: g.append("</div></center>");
0814:
0815: if (!nofile && !showdirs) {
0816: no_entries = false;
0817: // now generate the form
0818: g.append("<center>");
0819: g.append("<form OnSubmit=\"return(accFileSub());\" "
0820: + "name=\"liste\" action=\"",
0821: resource.getURLPath(), "\" method=\"post\">\n");
0822: g
0823: .append(
0824: "<table width=\"90%\" border=\"0\" cellspacing=\"0\"",
0825: "cellpadding=\"0\" nosave>\n");
0826: g.append("<caption>FILES in ", parentpath, "</caption>\n");
0827: // Dump entries, sorted:
0828: int alphaidx = 0;
0829: for (int i = 0; i < names.size(); i++) {
0830: String name = (String) names.elementAt(i);
0831: char ch = name.charAt(0);
0832: if (Character.isLetterOrDigit(ch)) {
0833: if ((alphaidx == 0)
0834: || (ch != alphabet[alphaidx - 1])) {
0835: char alpha = alphabet[alphaidx];
0836: while (ch != alpha) {
0837: g
0838: .append("<a name=\"" + alpha
0839: + "\"></a>\n");
0840: alpha = alphabet[++alphaidx];
0841: }
0842: if (ch == alpha) {
0843: g
0844: .append("<a name=\"" + alpha
0845: + "\"></a>\n");
0846: alphaidx++;
0847: }
0848: }
0849: }
0850: try {
0851: dumpFileEntry(g, name);
0852: } catch (CvsException ex) {
0853: g.append("<td>" + name
0854: + "<strong>CVS Failed</strong>\n");
0855: }
0856: }
0857: g.append("<tr><td colspan=\"2\">");
0858: g.append("</center><a class=\"script\" "
0859: + "href=\"javascript:SelectAll()\" "
0860: + "onMouseOver=\"window.status="
0861: + "'Select / Unselect all files';"
0862: + "return true\">All/None</a><center>");
0863: g.append("</td></tr>");
0864: g.append("</table><p>\n");
0865:
0866: // Dump the files command area:
0867: g.append("<hr noshade width=\"40%\">");
0868: g.append("<table cellpadding=\"10\" align=\"center\" "
0869: + "width=\"90%\" border=\"0\" cellspacing=\"0\" "
0870: + "cellpadding=\"0\">");
0871: // add proposed actions
0872: g.append("<tr valign=\"top\"><td>");
0873: g.append("<strong>Action:</strong><br>\n");
0874: g
0875: .append("<input type=\"radio\" name=\"action\" value=\"addcom\">"
0876: + " Add into the repository <br>\n");
0877: g
0878: .append("<input type=\"radio\" name=\"action\" value=\"commit\">"
0879: + " Incorporate changes into the repository <br>\n");
0880: g
0881: .append("<input type=\"radio\" name=\"action\" value=\"update\" "
0882: + "checked = \"yes\"> Update <br>\n");
0883: g
0884: .append("<input type=\"radio\" name=\"action\" value=\"revert\">"
0885: + " Revert to selected revision <br>\n");
0886: g
0887: .append("<input type=\"radio\" name=\"action\" value=\"remove\">"
0888: + " Remove from repository <br>\n");
0889: g.append("</td>\n<td>\n");
0890: // add proposed scopes:
0891: g.append("<strong>Perform action on:</strong><br>\n\n");
0892: g
0893: .append("<input type=\"radio\" name=\"scope\" value=\"mark\""
0894: + "checked=\"yes\"> Marked files<br>\n");
0895: g.append("<input type=\"radio\" name=\"scope\" "
0896: + "value=\"directory\"> Directory<br>\n");
0897: g
0898: .append("<input type=\"radio\" name=\"scope\" value=\"regexp\">"
0899: + " Matching files <input type=\"text\" name=\"regval\">"
0900: + "<br>\n");
0901: g.append("</td></tr>");
0902: // comments
0903: g.append("<tr><td colspan=2 align=\"center\">\n");
0904: g.append("<p align=\"center\"><strong>Comments for "
0905: + "add/remove/commit files<br>\n");
0906: g
0907: .append("<textarea wrap=\"soft\" name=\"comment\" rows=\"3\" "
0908: + "cols=\"50\">\n");
0909: g.append("</textarea></td></tr>\n");
0910: // and close the table and the first form
0911: g.append("<tr valign=\"top\"><td align=\"center\" "
0912: + "colspan=\"2\">\n");
0913: g.append("<input type=\"submit\" name=\"submit\" "
0914: + "value=\" Perform Action \" "
0915: + "onClick=\"confirmFileAction();\">");
0916: g.append("</table>");
0917: g.append("</form>\n\n");
0918: g.append("</table>");
0919: g.append("</center>\n");
0920: }
0921:
0922: if (!nodir && showdirs) {
0923: no_entries = false;
0924: // the next one is for stephan
0925: g.append("<A NAME=\"dirs\"></A>");
0926: // now generate the form
0927: g.append("<center>\n");
0928: g
0929: .append(
0930: "<form OnSubmit=\"return(accDirSub());\" name=\"liste\"",
0931: " method=\"post\">\n");
0932: //g.append("<table width=\"80%\">\n") ;
0933: g
0934: .append(
0935: "<table width=\"90%\" border=\"0\" cellspacing=\"0\"",
0936: "cellpadding=\"0\">\n");
0937: g.append("<caption>SUBDIRECTORIES in ", parentpath,
0938: "</caption>\n");
0939: // Dump entries, sorted:
0940: int alphaidx = 0;
0941: for (int i = 0; i < dirnames.size(); i++) {
0942: String name = (String) dirnames.elementAt(i);
0943: char ch = name.charAt(0);
0944: if (Character.isLetterOrDigit(ch)) {
0945: if ((alphaidx == 0)
0946: || (ch != alphabet[alphaidx - 1])) {
0947: char alpha = alphabet[alphaidx];
0948: while (ch != alpha) {
0949: g
0950: .append("<a name=\"" + alpha
0951: + "\"></a>\n");
0952: alpha = alphabet[++alphaidx];
0953: }
0954: if (ch == alpha) {
0955: g
0956: .append("<a name=\"" + alpha
0957: + "\"></a>\n");
0958: alphaidx++;
0959: }
0960: }
0961: }
0962: try {
0963: dumpDirectoryEntry(g, name);
0964: } catch (CvsException e) {
0965: g.append("<td>" + name
0966: + "<strong>CVS Failed</strong>\n");
0967: }
0968: }
0969: g.append("<tr><td colspan=\"2\">");
0970: g.append("</center><a class=\"script\" "
0971: + "href=\"javascript:SelectAll()\" "
0972: + "onMouseOver=\"window.status="
0973: + "'Select / Unselect all files';"
0974: + "return true\">All/None</a><center>");
0975: g.append("</td></tr>");
0976: g.append("</table><p>\n");
0977: // Dump the dirs command area:
0978: g
0979: .append("<table align=\"center\" width=\"90%\" width=\"90%\" "
0980: + "border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
0981: g
0982: .append("<input type=\"hidden\" name=\"action\" value=\"add\">");
0983: //hidden scope
0984: g.append("<input type=\"hidden\" name=\"scope\""
0985: + " value=\"subdir\">\n");
0986: g.append("<tr><td align=\"center\">",
0987: "<input type=\"submit\" name=\"submit\" ",
0988: "value=\"Add marked directories\" "
0989: + "onClick=\"confirmDirAction();\">\n"
0990: + "</td></tr>");
0991: // and close the table and the first form
0992: g.append("</table></form>\n\n");
0993: g.append("</center>\n");
0994: }
0995: if (no_entries) {
0996: g.append("<center>No entries.</center><p>\n");
0997: //new
0998: g.append("<form name=\"liste\"" + "action=\"", resource
0999: .getURLPath(), "\" method=\"post\">\n");
1000: g.append("<table cellpadding=\"10\" align=\"center\" "
1001: + "width=\"90%\" border=\"0\" cellspacing=\"0\" "
1002: + "cellpadding=\"0\">");
1003: // add proposed actions
1004: g.append("<tr valign=\"top\"><td>");
1005: g.append("<input type=\"hidden\" name=\"action\" ",
1006: "value=\"update\">");
1007: // add proposed scopes:
1008: g.append("<strong>Perform update on:</strong><br>\n\n");
1009: g.append("<input type=\"radio\" name=\"scope\" "
1010: + "value=\"directory\"> Directory<br>\n");
1011: g
1012: .append("<input type=\"radio\" name=\"scope\" value=\"regexp\">"
1013: + " File <input type=\"text\" name=\"regval\">"
1014: + "<br>\n");
1015: g.append("</td></tr>");
1016: // and close the table and the first form
1017: g.append("<tr valign=\"top\"><td align=\"center\" "
1018: + "colspan=\"2\">\n");
1019: g.append("<input type=\"submit\" name=\"submit\" "
1020: + "value=\" Update \">");
1021: g.append("</td></tr></table>");
1022: g.append("</form>\n\n");
1023: //end new
1024: } else {
1025: g.append("<a name=\"bottom\"></a>");
1026: g.append("<center><hr noshade width=\"80%\">", head,
1027: "</center>");
1028: }
1029:
1030: g.close();
1031: // Send back the reply:
1032: Reply reply = request.makeReply(HTTP.OK);
1033: reply.setHeaderValue(reply.H_CACHE_CONTROL,
1034: CACHE_CONTROL_NOCACHE);
1035: reply.setHeaderValue(reply.H_PRAGMA, PRAGMA_NOCACHE);
1036: reply.setStream(g);
1037: return reply;
1038: }
1039:
1040: protected String getAction(Request request) throws HTTPException {
1041: String query = request.getQueryString();
1042: if (query == null)
1043: return "unknown";
1044: InputStream in = new StringBufferInputStream(query);
1045: URLDecoder d = new URLDecoder(in, getOverrideFlag());
1046: try {
1047: d.parse();
1048: } catch (URLDecoderException e) {
1049: Reply error = request.makeReply(HTTP.BAD_REQUEST);
1050: error
1051: .setContent("Invalid request:unable to decode form data.");
1052: throw new HTTPException(error);
1053: } catch (IOException e) {
1054: Reply error = request.makeReply(HTTP.BAD_REQUEST);
1055: error
1056: .setContent("Invalid request: unable to read form data.");
1057: throw new HTTPException(error);
1058: }
1059:
1060: String action = d.getValue("action");
1061: return (action == null ? "unknown" : action);
1062: }
1063:
1064: /**
1065: * This is were we handle the big post request.
1066: * @exception ProtocolException if a protocol error occurs
1067: */
1068: public Reply handle(Request request,
1069: org.w3c.jigsaw.forms.URLDecoder data)
1070: throws ProtocolException {
1071: String action = data.getValue("action");
1072: String scope = data.getValue("scope");
1073:
1074: // no action, is a bug in the generated form (see get)
1075: if (action == null) {
1076: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);
1077: error.setContent("No action selected !");
1078: throw new HTTPException(error);
1079: }
1080:
1081: // Check action's scope:
1082: Enumeration gen_enum = null;
1083: Vector targets = new Vector();
1084:
1085: if (scope.equals("directory")) {
1086: // Apply action to the whole directory:
1087: return performDirectoryAction(action, request, data);
1088: } else if (scope.equals("subdir")) {
1089: // Apply action to the subdirectories
1090: // Get the list of targets to act on:
1091: try {
1092: gen_enum = getCvsManager().listDirectories();
1093: } catch (CvsException ex) {
1094: error(this , request, "unable to list directories", ex);
1095: }
1096: } else {
1097: // Apply action to the files
1098: // Get the list of targets to act on:
1099: try {
1100: gen_enum = getCvsManager().listFiles();
1101: } catch (CvsException ex) {
1102: error(this , request, "unable to list files", ex);
1103: }
1104: }
1105:
1106: if (scope.equals("regexp")) {
1107: // direct perform
1108: String regval = (String) data.getValue("regval");
1109: String comment = (String) data.getValue("comment");
1110: if (action.equals("remove") || action.equals("revert")) {
1111: throw new HTTPException(error(this , request,
1112: "Can't perform " + action
1113: + " with regular expression.",
1114: "<center><b>" + regval + "</b></center>"));
1115: }
1116: // direct perform
1117: if (comment != null)
1118: handler.perform(request, action, regval, comment);
1119: else
1120: handler.perform(request, action, regval);
1121: } else {
1122: while (gen_enum.hasMoreElements()) {
1123: String name = (String) gen_enum.nextElement();
1124: if (data.getValue(name) != null)
1125: targets.addElement(name);
1126: }
1127:
1128: // Perform that action:
1129: int size = targets.size();
1130: if (size > 0) {
1131: String names[] = new String[size];
1132: String revs[] = new String[size];
1133: targets.copyInto(names);
1134: for (int i = 0; i < size; i++)
1135: revs[i] = data.getValue(names[i] + ".rev");
1136: // Perform the comand :
1137: String comment = data.getValue("comment");
1138:
1139: if (action.equals("remove")) {
1140: //get the parent resource of our own resource
1141: ResourceReference rr = getResource().getParent();
1142: try {
1143: Resource res = rr.lock();
1144: DirectoryResource dirres = null;
1145: if (!(res instanceof DirectoryResource)) {
1146: getServer()
1147: .errlog(res,
1148: "CvsFrame: not a child of a DirectoryResource");
1149: return error(this , request,
1150: "The server is misconfigured.",
1151: "The CVS Directory is not a children of a"
1152: + "Directory Resource.");
1153: }
1154: dirres = (DirectoryResource) res;
1155: for (int i = 0; i < size; i++) {
1156: String name = names[i];
1157: ResourceReference childref = dirres
1158: .lookup(name);
1159: if (childref != null) {
1160: try {
1161: Resource children = childref.lock();
1162: if (children instanceof FileResource) {
1163: FileResource fres = (FileResource) children;
1164: // delete the file
1165: fres.getFile().delete();
1166: // delete the resource
1167: fres.delete();
1168: }
1169: } catch (MultipleLockException mex) {
1170: mex.printStackTrace();
1171: return error(
1172: this ,
1173: request,
1174: "MultipleLockException: "
1175: + mex.getMessage(),
1176: "Resource "
1177: + name
1178: + " in use"
1179: + ", can't be deleted now.");
1180: } catch (InvalidResourceException iex) {
1181: iex.printStackTrace();
1182: return error(
1183: this ,
1184: request,
1185: "InvalidResourceException. ",
1186: iex.getMessage());
1187: } catch (Exception ex) {
1188: ex.printStackTrace();
1189: return error(this , request,
1190: "Exception occurs.", ex
1191: .getMessage());
1192: } finally {
1193: childref.unlock();
1194: }
1195: } else {
1196: //no resource, remove the file only
1197: File file = new File(dirres
1198: .getDirectory(), name);
1199: file.delete();
1200: }
1201: }
1202: } catch (InvalidResourceException ex) {
1203: ex.printStackTrace();
1204: } finally {
1205: rr.unlock();
1206: }
1207: }
1208:
1209: if (comment != null)
1210: handler.perform(request, action, names, revs,
1211: comment);
1212: else
1213: handler.perform(request, action, names, revs);
1214: }
1215: }
1216: return get(request);
1217: }
1218:
1219: }
|