| /******************************************************************************* |
| * Copyright (c) 2014 CohesionForce Inc |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * CohesionForce Inc - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ecf.internal.provider.filetransfer.scp; |
| |
| import com.jcraft.jsch.ChannelExec; |
| import com.jcraft.jsch.Session; |
| import java.io.*; |
| import java.net.*; |
| import java.util.*; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ecf.core.identity.IDFactory; |
| import org.eclipse.ecf.core.security.IConnectContext; |
| import org.eclipse.ecf.core.util.Proxy; |
| import org.eclipse.ecf.filetransfer.IRemoteFile; |
| import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener; |
| import org.eclipse.ecf.filetransfer.identity.*; |
| import org.eclipse.ecf.provider.filetransfer.browse.AbstractFileSystemBrowser; |
| import org.eclipse.ecf.provider.filetransfer.browse.URLRemoteFile; |
| import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; |
| |
| /** |
| * The ScpFileSystemBrowser uses the JCraft JSch package to run remote commands |
| * using SSH to list files in a directory. |
| * |
| */ |
| public class ScpFileSystemBrowser extends AbstractFileSystemBrowser implements |
| IScpFileTransfer { |
| |
| protected InputStream inputStream; |
| |
| protected OutputStream outputStream; |
| |
| protected ScpUtil scpUtil; |
| |
| protected ChannelExec channel; |
| protected String username; |
| |
| protected static final String SCP_EXEC = System.getProperty( |
| "org.eclipse.ecf.filetransfer.scp.filebrowse.exec", "exec"); //$NON-NLS-1$ |
| protected static final String LS_START_COMMAND = System.getProperty( |
| "org.eclipse.ecf.filetransfer.scp.filebrowse.lscommand.start", |
| "IFS=\"$(printf '\n\t\')\"; shopt -s dotglob; for file in "); //$NON-NLS-1$; //$NON-NLS-1$ |
| protected static final String LS_END_COMMAND = System.getProperty( |
| "org.eclipse.ecf.filetransfer.scp.filebrowse.lscommand.end", |
| "/*; do stat --format='%F|%s|%Y|%n' $file; done "); //$NON-NLS-1$; //$NON-NLS-1$ |
| |
| /** |
| * Constructor for creating a ScpFileSystemBrowser. |
| * |
| * @param directoryOrFileID |
| * - ID of the remote location to browse |
| * @param listener |
| * - will be called asynchronously with events resulting from |
| * file browsing. |
| * @param url |
| * - URL of the parent directory to browse. |
| * @param connectContext |
| * - contains username/password to use for the ssh connection |
| * @param proxy |
| * - proxy to be used if set. |
| */ |
| public ScpFileSystemBrowser(IFileID directoryOrFileID, |
| IRemoteFileSystemListener listener, URL url, |
| IConnectContext connectContext, Proxy proxy) { |
| super(directoryOrFileID, listener, url, connectContext, proxy); |
| username = directoryOrFile.getUserInfo(); |
| } |
| |
| /** |
| * Method called from super class to build the list of remote files. |
| */ |
| protected void runRequest() throws Exception { |
| scpUtil = new ScpUtil(this); |
| final Session s = scpUtil.getSession(); |
| s.connect(); |
| if (s.isConnected()) { |
| final String targetFileName = scpUtil |
| .trimTargetFile(directoryOrFile.getPath()); |
| final String command = LS_START_COMMAND + targetFileName |
| + LS_END_COMMAND; |
| channel = (ChannelExec) s.openChannel(SCP_EXEC); |
| channel.setCommand(command); |
| final OutputStream outs = channel.getOutputStream(); |
| inputStream = channel.getInputStream(); |
| channel.connect(); |
| |
| setOutputStream(outs); |
| |
| BufferedReader reader = new BufferedReader(new InputStreamReader( |
| inputStream)); |
| String line = reader.readLine(); |
| ArrayList strings = new ArrayList(); |
| while (line != null) { |
| strings.add(line); |
| line = reader.readLine(); |
| } |
| List remoteFilesList = new ArrayList(); |
| for (int i = 0; i < strings.size(); i++) { |
| try { |
| remoteFilesList.add(createRemoteFile((String) strings |
| .get(i))); |
| } catch (Exception e) { |
| Activator |
| .getDefault() |
| .log(new Status( |
| IStatus.ERROR, |
| Activator.PLUGIN_ID, |
| IStatus.ERROR, |
| "SCPFileBrowser could not convert string '" + ((String) strings.get(i)) + "' to FileID", e)); //$NON-NLS-1$ |
| } |
| } |
| remoteFiles = (IRemoteFile[]) remoteFilesList |
| .toArray(new IRemoteFile[remoteFilesList.size()]); |
| } |
| } |
| |
| private IRemoteFile createRemoteFile(String string) |
| throws URISyntaxException, FileCreateException, SecurityException { |
| URLRemoteFile file = null; |
| IFileID id = null; |
| String[] parts = string.split("\\|"); |
| |
| // Check to see if this string can be parsed |
| if (parts.length < 4) { |
| id = FileIDFactory.getDefault().createFileID( |
| IDFactory.getDefault().getNamespaceByName( |
| FileTransferNamespace.PROTOCOL), "scp://unknown"); |
| file = new URLRemoteFile(0, 0, id); |
| } else { |
| |
| // Build the filename back up, since the filename may also contain |
| // "|" |
| // characters |
| StringBuilder builder = new StringBuilder("scp://"); |
| for (int i = 3; i < parts.length; i++) { |
| builder.append(parts[i]); |
| |
| // Put the | back into the name |
| if (i > 3 && i < parts.length - 1) { |
| builder.append("|"); |
| } |
| } |
| |
| // If it's a directory, then make sure it ends with / |
| if (parts[0].equals("directory") |
| && !builder.toString().endsWith("/")) { |
| builder.append("/"); |
| } else if (!parts[0].equals("directory") |
| && builder.toString().endsWith("/")) { |
| builder.deleteCharAt(builder.length() - 1); |
| } |
| |
| String originalName = builder.toString(); |
| String formatedName = originalName.replace(" ", "%20"); |
| URI uri = new URI(formatedName); |
| |
| // Create the FileID |
| id = FileIDFactory.getDefault().createFileID( |
| IDFactory.getDefault().getNamespaceByName( |
| FileTransferNamespace.PROTOCOL), |
| new Object[] { uri }); |
| long size = Long.parseLong(parts[1]); |
| long modification = Long.parseLong(parts[2]); |
| file = new URLRemoteFile(modification, size, id); |
| } |
| return file; |
| } |
| |
| protected void cleanUp() { |
| super.cleanUp(); |
| if (channel != null) { |
| channel.disconnect(); |
| channel = null; |
| } |
| if (scpUtil != null) { |
| scpUtil.dispose(); |
| scpUtil = null; |
| } |
| try { |
| if (inputStream != null) |
| inputStream.close(); |
| } catch (final IOException e) { |
| Activator.getDefault().log( |
| new Status(IStatus.ERROR, Activator.PLUGIN_ID, |
| IStatus.ERROR, "cleanup", e)); //$NON-NLS-1$ |
| } |
| try { |
| if (outputStream != null) |
| outputStream.close(); |
| } catch (final IOException e) { |
| Activator.getDefault().log( |
| new Status(IStatus.ERROR, Activator.PLUGIN_ID, |
| IStatus.ERROR, "cleanup", e)); //$NON-NLS-1$ |
| } |
| inputStream = null; |
| outputStream = null; |
| } |
| |
| protected void setupProxy(Proxy proxy) { |
| this.proxy = proxy; |
| this.setupProxies(); |
| } |
| |
| protected void setInputStream(InputStream ins) { |
| inputStream = ins; |
| } |
| |
| protected void setOutputStream(OutputStream outs) { |
| outputStream = outs; |
| } |
| |
| public IConnectContext getConnectContext() { |
| return connectContext; |
| } |
| |
| public String getUsername() { |
| return username; |
| } |
| |
| public void setUsername(String username) { |
| this.username = username; |
| } |
| |
| public Proxy getProxy() { |
| return proxy; |
| } |
| |
| public URL getTargetURL() { |
| return directoryOrFile; |
| } |
| |
| public Map getOptions() { |
| return null; |
| } |
| |
| } |