package er.extensions.components; import java.io.File; import java.io.IOException; import org.apache.commons.lang3.StringUtils; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOResponse; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableArray; import com.webobjects.foundation.NSPathUtilities; import er.extensions.foundation.ERXArrayUtilities; import er.extensions.foundation.ERXRuntimeUtilities; import er.extensions.foundation.ERXRuntimeUtilities.Result; import er.extensions.foundation.ERXRuntimeUtilities.TimeoutException; import er.extensions.foundation.ERXStringUtilities; import er.extensions.foundation.ERXSystem; /** * * @property java.io.tmpdir used for the default upload directory */ public class ERXRemoteShell extends WOComponent { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private static String alternativeQuote = "!#ALT_QUOTE#!"; public String dir = "/"; public String selectedPath; public NSMutableArray pathHistory = new NSMutableArray(); public String currentPath; public int timeout = 3 * 60 * 1000; // 3 minutes public String envp; public String uploadPath = ERXSystem.getProperty("java.io.tmpdir"); public String consoleText = null; public String consoleTextHistory = null; public String command = null; // file upload stuff public String filePath; public String finalFilePath; public String mimeType; public String streamToFilePath() { return new File(uploadPath, NSPathUtilities.lastPathComponent(filePath)).getAbsolutePath(); } public ERXRemoteShell(WOContext context) { super(context); } @Override public void appendToResponse(WOResponse r, WOContext c) { if (session().objectForKey("ERXRemoteShell.enabled") != null) { dir = ""; super.appendToResponse(r, c); } else { r.appendContentString("please use the ERXDirectAction remoteShellAction to login first!"); } } public WOComponent execute() { if (ERXStringUtilities.stringIsNullOrEmpty(dir)) { dir = selectedPath; } else if (!pathHistory.containsObject(dir)) { pathHistory.addObject(dir); } // get the new command String[] commandArray = buildCommandArray(command); String[] envpArray = buildEnvpArray(envp); if (envpArray == null || envpArray.length == 0) { envpArray = new String[] { "TEST=t" }; } if (ERXStringUtilities.stringIsNullOrEmpty(dir)) { dir = "/"; } try { Result result = ERXRuntimeUtilities.execute(commandArray, envpArray, new File(dir), timeout); String response = result.getResponseAsString(); consoleText = "\n" + response; consoleTextHistory += "\n"; consoleTextHistory += "\n"; consoleTextHistory += "<b>"+command+"</b>"; consoleTextHistory += "\n"; consoleTextHistory += consoleText; return context().page(); } catch (IOException e) { consoleText += "\n"; consoleText += "an exception occured"; consoleText += "\n"; consoleText += e.getMessage(); return context().page(); } catch (TimeoutException e) { consoleText += "\n"; consoleText += "process did not timeout after " + timeout + " seconds"; return context().page(); } } public WOComponent clearConsole() { consoleText = ""; consoleTextHistory = ""; return context().page(); } public WOComponent uploadFile() { return context().page(); } private static String[] buildEnvpArray(String envp) { NSArray a = NSArray.componentsSeparatedByString(envp, Character.LINE_SEPARATOR + ""); return ERXArrayUtilities.toStringArray(a); } private static String[] buildCommandArray(String command) { String newCommand = StringUtils.replace(command, "\\\"", alternativeQuote); NSMutableArray a = new NSMutableArray(); StringBuilder buf = new StringBuilder(); int length = newCommand.length(); boolean insideQuote = false; for (int i = 0; i < length; i++) { char c = newCommand.charAt(i); if ('"' == c) { if (insideQuote) { // quoted string ends here String s = buf.toString().replaceAll(alternativeQuote, "\""); if (s.length() > 0) { a.addObject(s); } buf = new StringBuilder(); } else { // quoted string starts here insideQuote = true; buf = new StringBuilder(); } } else if (' ' == c) { if (insideQuote) { // space inside a quoted string is OK buf.append(c); } else { // string sequence ends here String s = buf.toString().replaceAll(alternativeQuote, "\""); if (s.length() > 0) { a.addObject(s); } buf = new StringBuilder(); } } else { buf.append(c); } } if (buf.length() > 0) a.addObject(buf.toString().replaceAll(alternativeQuote, "\"")); return ERXArrayUtilities.toStringArray(a); } }