diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/.classpath b/rse/plugins/org.eclipse.rse.connectorservice.ssh/.classpath new file mode 100644 index 00000000000..751c8f2e504 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/.project b/rse/plugins/org.eclipse.rse.connectorservice.ssh/.project new file mode 100644 index 00000000000..dfdb5f84dd4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.connectorservice.ssh + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.connectorservice.ssh/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..5ee380b868f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Ssh Plug-in +Bundle-SymbolicName: org.eclipse.rse.connectorservice.ssh; singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.rse.connectorservice.ssh.Activator +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.rse.services, + org.eclipse.rse.core, + org.eclipse.rse.ui, + com.jcraft.jsch, + org.eclipse.team.cvs.ssh, + org.eclipse.team.cvs.ssh2, + org.eclipse.team.cvs.ui, + org.eclipse.rse.services.ssh +Eclipse-LazyStart: true +Export-Package: org.eclipse.rse.connectorservice.ssh diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/build.properties b/rse/plugins/org.eclipse.rse.connectorservice.ssh/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.properties b/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.properties new file mode 100644 index 00000000000..d6e46520e8f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.properties @@ -0,0 +1,16 @@ +################################################################################ +# Copyright (c) 2006 Wind River Systems, 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: +# Martin Oberhuber - initial API and implementation +################################################################################ + +plugin.name = Ssh Connector Service Plugin + +SshSystemName=SSH Only +SshSystemDescription=Connection for SSH access to remote hosts + diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.xml b/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.xml new file mode 100644 index 00000000000..1c088bcb81d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/plugin.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/Activator.java b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/Activator.java new file mode 100644 index 00000000000..e6ba9c4f63c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/Activator.java @@ -0,0 +1,61 @@ +package org.eclipse.rse.connectorservice.ssh; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.rse.connectorservice.ssh"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/ISshSubSystem.java b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/ISshSubSystem.java new file mode 100644 index 00000000000..ed716c1efd2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/ISshSubSystem.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.connectorservice.ssh; + +/** + * Markup Interface for subsystems using the SshConnectorService. + * + * By implementing this interface, subsystems can be recognized + * as being able to share a single ssh connector service between + * multiple different subsystems. + */ +public interface ISshSubSystem { + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorService.java b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorService.java new file mode 100644 index 00000000000..951c698d0c8 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorService.java @@ -0,0 +1,273 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, Inc. and others. + * 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.connectorservice.ssh; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.rse.core.subsystems.AbstractConnectorService; +import org.eclipse.rse.model.IHost; +import org.eclipse.rse.services.files.IFileService; +import org.eclipse.swt.widgets.Display; +import org.eclipse.team.internal.ccvs.ssh2.CVSSSH2Plugin; +import org.eclipse.team.internal.ccvs.ssh2.ISSHContants; +import org.eclipse.team.internal.ccvs.ui.UserValidationDialog; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.UserInfo; +import org.eclipse.rse.services.ssh.ISshSessionProvider; + +/** + * Create SSH connections. + */ +public class SshConnectorService extends AbstractConnectorService implements ISshSessionProvider +{ + private static final int SSH_DEFAULT_PORT = 22; + private static JSch jsch=new JSch(); + private Session session; +// protected SftpFileService _sftpFileService; + + public SshConnectorService(IHost host) { + //TODO the port parameter doesnt really make sense here since + //it will be overridden when the subsystem initializes (through + //setPort() on our base class -- I assume the port is meant to + //be a local port. + super("SSH Connector Service", "SSH Connector Service Description", host, 0); + // _sftpFileService = new SftpFileService(this); + } + + //---------------------------------------------------------------------- + // + //---------------------------------------------------------------------- + private static String current_ssh_home = null; + private static String current_pkeys = ""; //$NON-NLS-1$ + + static String SSH_HOME_DEFAULT = null; + static { + String ssh_dir_name = ".ssh"; //$NON-NLS-1$ + + // Windows doesn't like files or directories starting with a dot. + if (Platform.getOS().equals(Platform.OS_WIN32)) { + ssh_dir_name = "ssh"; //$NON-NLS-1$ + } + SSH_HOME_DEFAULT = System.getProperty("user.home"); //$NON-NLS-1$ + if (SSH_HOME_DEFAULT != null) { + SSH_HOME_DEFAULT = SSH_HOME_DEFAULT + java.io.File.separator + ssh_dir_name; + } + } + + static void loadSshPrefs() + { + IPreferenceStore store = CVSSSH2Plugin.getDefault().getPreferenceStore(); + String ssh_home = store.getString(ISSHContants.KEY_SSH2HOME); + String pkeys = store.getString(ISSHContants.KEY_PRIVATEKEY); + + try { + if (ssh_home.length() == 0) + ssh_home = SSH_HOME_DEFAULT; + + if (current_ssh_home == null || !current_ssh_home.equals(ssh_home)) { + loadKnownHosts(ssh_home); + current_ssh_home = ssh_home; + } + + if (!current_pkeys.equals(pkeys)) { + java.io.File file; + String[] pkey = pkeys.split(","); //$NON-NLS-1$ + String[] _pkey = current_pkeys.split(","); //$NON-NLS-1$ + current_pkeys = ""; //$NON-NLS-1$ + for (int i = 0; i < pkey.length; i++) { + file = new java.io.File(pkey[i]); + if (!file.isAbsolute()) { + file = new java.io.File(ssh_home, pkey[i]); + } + if (file.exists()) { + boolean notyet = true; + for (int j = 0; j < _pkey.length; j++) { + if (pkey[i].equals(_pkey[j])) { + notyet = false; + break; + } + } + if (notyet) + jsch.addIdentity(file.getPath()); + if (current_pkeys.length() == 0) { + current_pkeys = pkey[i]; + } else { + current_pkeys += ("," + pkey[i]); //$NON-NLS-1$ + } + } + } + } + } catch (Exception e) { + } + + } + + static void loadKnownHosts(String ssh_home){ + try { + java.io.File file; + file=new java.io.File(ssh_home, "known_hosts"); //$NON-NLS-1$ + jsch.setKnownHosts(file.getPath()); + } catch (Exception e) { + } + } + + //---------------------------------------------------------------------- + // + //---------------------------------------------------------------------- + + protected void internalConnect(IProgressMonitor monitor) throws Exception + { + //TODO Set known hosts and identities from Preferences + //We could share the preferences from ssh2, or use RSE + //ConnectorService Properties / Server Launcher Properties + + //jsch.setKnownHosts("/home/foo/.ssh/known_hosts"); + loadSshPrefs(); + String host = getHostName(); + String user = getUserId(); + + session=jsch.getSession(user, host, SSH_DEFAULT_PORT); + session.setPassword(getPasswordInformation().getPassword()); + //session.setPassword("your password"); + + // username and password will be given via UserInfo interface. + UserInfo ui=new MyUserInfo(user); + session.setUserInfo(ui); + + //java.util.Hashtable config=new java.util.Hashtable(); + //config.put("StrictHostKeyChecking", "no"); + //session.setConfig(config); + session.connect(3000); // making connection with timeout. + + //now also connect the sftpFileService. It's not very nice to force + //the connector service know about the file service, and connect it + //so early -- lazy connect inside the sftpFileService would be better. + //But the FileServiceSubsystem only calls internalConnect() on the + //connector service, and doesn't try to connect the file service + //individually. + //TODO: From the API point of view, it might be better if the file + //service had a connect() method and could decide itself if and how + //it wants to use the connector service. + //Or could we ensure that the FileService is instanciated only once + //it needs to be connected? - Currently this is not the case (it is + //instanciated very early by the subsystem). + // _sftpFileService.connect(); + } + + public void internalDisconnect(IProgressMonitor monitor) + { + //TODO: Check, Is disconnect being called because the network (connection) went down? + //TODO: Fire communication event (aboutToDisconnect) -- see DStoreConnectorService.internalDisconnect() + //TODO: Wrap exception in an InvocationTargetException -- see DStoreConnectorService.internalDisconnect() + // _sftpFileService.disconnect(); + session.disconnect(); + } + + //TODO avoid having jsch type "Session" in the API. + //Could be done by instanciating SshShellService and SshFileService here, + //and implementing IShellService getShellService() + //and IFileService getFileService(). + public Session getSession() { + return session; + } + /* + public IFileService getFileService() { + return _sftpFileService; + } + */ + + private static Display getStandardDisplay() { + Display display = Display.getCurrent(); + if( display==null ) { + display = Display.getDefault(); + } + return display; + } + + private static class MyUserInfo implements UserInfo { + String fPassphrase; + String fPassword; + final String fUser; + + public MyUserInfo(String user) { + fUser = user; + } + public String getPassword() { + return fPassword; + } + public boolean promptYesNo(final String str) { + //need to switch to UI thread for prompting + final boolean[] retval = new boolean[1]; + getStandardDisplay().syncExec(new Runnable() { + public void run() { + retval[0] = MessageDialog.openQuestion(null, "Warning", str); + } + }); + return retval[0]; + } + private String promptString(final String message) { + final String[] retval = new String[1]; + getStandardDisplay().syncExec(new Runnable() { + public void run() { + //TODO Write our own UserValidationDialog instead of re-using the internal one from team.ssh + UserValidationDialog uvd = new UserValidationDialog(null, null, + fUser, message); + uvd.setUsernameMutable(false); + if (uvd.open() == uvd.OK) { + retval[0] = uvd.getPassword(); + } else { + retval[0] = null; + } + } + }); + return retval[0]; + } + public String getPassphrase() { + return fPassphrase; + } + public boolean promptPassphrase(String message) { + fPassphrase = promptString(message); + return (fPassphrase!=null); + } + public boolean promptPassword(final String message) { + fPassword = promptString(message); + return (fPassphrase!=null); + } + public void showMessage(final String message) { + getStandardDisplay().syncExec(new Runnable() { + public void run() { + MessageDialog.openInformation(null, "Info", message); + } + }); + } + } + + public boolean isConnected() { + return (session!=null && session.isConnected()); + } + + public boolean hasRemoteServerLauncherProperties() { + return false; + } + + public boolean supportsRemoteServerLaunching() { + return false; + } + + public boolean supportsServerLaunchProperties() { + return false; + } + +} diff --git a/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorServiceManager.java b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorServiceManager.java new file mode 100644 index 00000000000..2c25e5cd976 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.connectorservice.ssh/src/org/eclipse/rse/connectorservice/ssh/SshConnectorServiceManager.java @@ -0,0 +1,66 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalConnectorServiceManager. + ********************************************************************************/ + +package org.eclipse.rse.connectorservice.ssh; + +import org.eclipse.rse.core.subsystems.AbstractConnectorServiceManager; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.model.IHost; + +/** + * ConnectorService manager class. + * + * The job of this manager is to manage and return IConnectorService + * objects. It ensures there is only ever one per unique SystemConnection, +* so that both the file and cmd subsystems can share the same +* ConnectorService object. + */ +public class SshConnectorServiceManager extends AbstractConnectorServiceManager { + + private static SshConnectorServiceManager fInstance; + + private SshConnectorServiceManager() { + super(); + } + + /** + * Return singleton instance of this class + */ + public static SshConnectorServiceManager getInstance() + { + if (fInstance == null) + fInstance = new SshConnectorServiceManager(); + return fInstance; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.core.subsystems.AbstractConnectorServiceManager#createConnectorService(org.eclipse.rse.model.IHost) + */ + public IConnectorService createConnectorService(IHost host) { + IConnectorService service = new SshConnectorService(host); + return service; + } + + public boolean sharesSystem(ISubSystem otherSubSystem) { + return (otherSubSystem instanceof ISshSubSystem); + } + + public Class getSubSystemCommonInterface(ISubSystem subsystem) { + return ISshSubSystem.class; + } + +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/.classpath b/rse/plugins/org.eclipse.rse.services.ssh/.classpath new file mode 100644 index 00000000000..751c8f2e504 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.services.ssh/.project b/rse/plugins/org.eclipse.rse.services.ssh/.project new file mode 100644 index 00000000000..9c78ce6c12d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.services.ssh + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..97d7c696e9f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %plugin.name +Bundle-SymbolicName: org.eclipse.rse.services.ssh;singleton:=true +Bundle-Version: 0.0.2 +Bundle-Activator: org.eclipse.rse.services.ssh.Activator +Bundle-Vendor: Eclipse.org +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.rse.services, + com.jcraft.jsch, + org.eclipse.team.cvs.ui, + org.eclipse.team.cvs.ssh2 +Eclipse-LazyStart: true +Export-Package: org.eclipse.rse.services.ssh, + org.eclipse.rse.services.ssh.files, + org.eclipse.rse.services.ssh.shell diff --git a/rse/plugins/org.eclipse.rse.services.ssh/about.html b/rse/plugins/org.eclipse.rse.services.ssh/about.html new file mode 100644 index 00000000000..12a49f13a6d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + diff --git a/rse/plugins/org.eclipse.rse.services.ssh/build.properties b/rse/plugins/org.eclipse.rse.services.ssh/build.properties new file mode 100644 index 00000000000..4c0e8fb61e4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/build.properties @@ -0,0 +1,10 @@ +bin.includes = .classpath,\ + .project,\ + about.html,\ + build.properties,\ + icons/,\ + META-INF/,\ + plugin.properties,\ + plugin.xml,\ + readme.txt,\ + src/ diff --git a/rse/plugins/org.eclipse.rse.services.ssh/readme.txt b/rse/plugins/org.eclipse.rse.services.ssh/readme.txt new file mode 100644 index 00000000000..4335f17a100 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/readme.txt @@ -0,0 +1,66 @@ +Readme for RSE ssh service +-------------------------- + +The RSE ssh plugin allows to connect the RSE Remote Command View to +a remote host through the secure shell (ssh) protocol. +This plugin is meant as a proof-of-concept. The code does not have +product quality yet, and there are lots of open issues (marked as +TODO in the code). But it is functional for setting up an ssh shell +connection. + +__Requirements:__ +The ssh service plugin has been tested with RSE M2 candidate +(CVS HEAD as of May 09, 2006) and Eclipse 3.2 RC3. +The Eclipse Platform Team / CVS feature is needed for the +com.jcraft.jsh plugin and the org.eclipse.team.cvs.ui plugin. + +__Installation:__ +You need an Eclipse PDE Workspace with RSE. +Then, choose File > Import > Existing Projects > Archive File, +to import the ssh service archive. + +__Usage:__ +* Start RSE, create a new system of type "SSH Only". +* If you store your ssh private keys in a non-standard place, use + Window > Preferences > Team > CVS > SSh2 Connection Method > General + to set the ssh home directory, and private key types to be used. +* Select the "Shells" node and choose Contextmenu > Launch Shell. +* Enter your username on the remote system. For the password, just + enter anything (this is not checked, since ssh has its own method + of acquiring password information). +* When asked to accept remote host authenticity, press OK. +* Enter the correct password for ssh on the remote system (this is only + necessary if you are not using a private key). + +__Known Limitations:__ +* Symbolic Links are not resolved (readlink not supported by jsch-0.1.28) +* Ssh passwords can not be stored (no key ring; use private keys instead) +* Ssh timeouts are not observed (no automatic reconnect) + - after auto-logout, shell just doesnt react to input any more +* Password and passphrase internal handling has not been checked for + security against malicious reading from other Eclipse plugins. + +__Known Issues:__ +* A dummy password must be entered on initial connect (can be saved) +* After some time, the connection may freeze and need to be + disconnected. +* Command service should be provided in addition to the remote shell service. +* Extremely long remote command output may lead to an Exception + due to memory exhaustion (ArrayIndexOutOfBoundsException) +* "Break" can not be sent to the remote system in order to cancel + long-running jobs on the remote side. +* Moving files with a space in the name doesn't currently work. + Renaming them works though. +* Copy&paste, or drag&drop of remote files remotely does'nt currently work. +* The plugin currently uses some "internal" classes from the + org.eclipse.team.cvs.ui plugin. This needs to be cleaned up. +* For other internal coding issues, see TODO items in the code. + +__Changelog:__ +v0.2: +* Re-use Team/CVS/ssh2 preferences for ssh2 home and private keys specification + Allows to do the ssh login without password if private/public key are set up. +* Key management from Team/CVS/ssh2 Preferences can also be used +* Add sftp files subsystem +* Fix status after disconnect operation +* Update about.html diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/Activator.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/Activator.java new file mode 100644 index 00000000000..f4103701368 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/Activator.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.services.ssh; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + + +/** + * The main plugin class to be used in the desktop. + */ +public class Activator extends AbstractUIPlugin { + + //The shared instance. + private static Activator plugin; + + /** + * The constructor. + */ + public Activator() { + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); +// make sure files.ui is activated +// org.eclipse.rse.files.ui.Activator.getDefault(); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + * + * @return the shared instance. + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.rse.services.ssh", path); + } +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshService.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshService.java new file mode 100644 index 00000000000..445a3a3354c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshService.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.services.ssh; + +/** + * Markup Interface for services using the SshConnectorService. + * + * By implementing this interface, services can be recognized + * as operating against an SshConnectorService. The interface + * is used as the key in a table for looking up the connector + * service when needed. + */ +public interface ISshService { + +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshSessionProvider.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshSessionProvider.java new file mode 100644 index 00000000000..9cfd1146f51 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/ISshSessionProvider.java @@ -0,0 +1,8 @@ +package org.eclipse.rse.services.ssh; + +import com.jcraft.jsch.Session; + +public interface ISshSessionProvider +{ + public Session getSession(); +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpFileService.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpFileService.java new file mode 100644 index 00000000000..2da95134cbd --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpFileService.java @@ -0,0 +1,451 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.services.ssh.files; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; + +import org.eclipse.rse.services.clientserver.NamePatternMatcher; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.files.AbstractFileService; +import org.eclipse.rse.services.files.IFileService; +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.rse.services.ssh.ISshService; +import org.eclipse.rse.services.ssh.ISshSessionProvider; + +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.SftpATTRS; +import com.jcraft.jsch.SftpProgressMonitor; + +public class SftpFileService extends AbstractFileService implements IFileService, ISshService +{ + //private SshConnectorService fConnector; + private ISshSessionProvider fSessionProvider; + private ChannelSftp fChannelSftp; + private String fUserHome; + +// public SftpFileService(SshConnectorService conn) { +// fConnector = conn; +// } + + public SftpFileService(ISshSessionProvider sessionProvider) { + fSessionProvider = sessionProvider; + } + + public String getName() { + return "Ssh / Sftp File Service"; + } + + public String getDescription() { + return "Access a remote file system via Ssh / Sftp protocol"; + } + + public void connect() throws Exception { + Session session = fSessionProvider.getSession(); + Channel channel=session.openChannel("sftp"); //$NON-NLS-1$ + channel.connect(); + fChannelSftp=(ChannelSftp)channel; + fUserHome = fChannelSftp.pwd(); + } + + public void disconnect() { + fChannelSftp.disconnect(); + fChannelSftp = null; + } + + public IHostFile getFile(IProgressMonitor monitor, String remoteParent, String fileName) + { + //TODO getFile() must return a dummy even for non-existent files, + //or the move() operation will fail. This needs to be described in + //the API docs. + SftpHostFile node = null; + SftpATTRS attrs = null; + try { + attrs = fChannelSftp.stat(remoteParent+'/'+fileName); + } catch(Exception e) {} + if (attrs!=null) { + node = makeHostFile(remoteParent, fileName, attrs); + } else { + node = new SftpHostFile(remoteParent, fileName, false, false, false, 0, 0); + node.setExists(false); + } + return node; + } + + public boolean isConnected() { + return fChannelSftp.isConnected(); + } + + protected IHostFile[] internalFetch(IProgressMonitor monitor, String parentPath, String fileFilter, int fileType) + { + if (fileFilter == null) { + fileFilter = "*"; //$NON-NLS-1$ + } + NamePatternMatcher filematcher = new NamePatternMatcher(fileFilter, true, true); + List results = new ArrayList(); + try { + java.util.Vector vv=fChannelSftp.ls(parentPath); + for(int ii=0; ii 0) + { + bos.write(buffer, 0, readCount); + } + bos.close(); + upload(monitor, tempFile, remoteParent, remoteFile, isBinary, "", hostEncoding); //$NON-NLS-1$ + } + catch (Exception e) { + //TODO See download + //e.printStackTrace(); + //throw new RemoteFileIOException(e); + return false; + } + return true; + } + + public boolean download(IProgressMonitor monitor, String remoteParent, String remoteFile, File localFile, boolean isBinary, String hostEncoding) throws SystemMessageException + { + try { + if (!localFile.exists()) { + File localParentFile = localFile.getParentFile(); + if (!localParentFile.exists()) { + localParentFile.mkdirs(); + } + //localFile.createNewFile(); + } + //TODO Ascii/binary? + String remotePath = remoteParent+'/'+remoteFile; + int mode=ChannelSftp.OVERWRITE; + MyProgressMonitor sftpMonitor = new MyProgressMonitor(monitor); + fChannelSftp.get(remotePath, localFile.getAbsolutePath(), sftpMonitor, mode); + } + catch (Exception e) { + //TODO handle exception properly: happens e.g. when trying to download a symlink. + //Messages from Jsch are mostly not useful, especially when the server version is + //<=3 (e.g. "4: Failure"). therefore it is better for now to just return false. + //e.printStackTrace(); + //throw new RemoteFileIOException(e); + return false; + } + return true; + } + + public IHostFile getUserHome() { + //TODO assert: this is only called after we are connected + int lastSlash = fUserHome.lastIndexOf('/'); + String name = fUserHome.substring(lastSlash + 1); + String parent = fUserHome.substring(0, lastSlash); + return getFile(null, parent, name); + } + + public IHostFile[] getRoots(IProgressMonitor monitor) { + IHostFile root = new SftpHostFile("/", "/", true, true, false, 0, 0); //$NON-NLS-1$ //$NON-NLS-2$ + return new IHostFile[] { root }; + } + + // TODO + /******************************************************** + * + * The following APIs need to be implemented + * + ********************************************************/ + + public IHostFile createFile(IProgressMonitor monitor, String remoteParent, String fileName) throws SystemMessageException + { + IHostFile result = null; + try { + String fullPath = remoteParent + '/' + fileName; + OutputStream os = fChannelSftp.put(fullPath); + os.close(); + SftpATTRS attrs = fChannelSftp.stat(fullPath); + result = makeHostFile(remoteParent, fileName, attrs); + } catch (Exception e) { + e.printStackTrace(); + // DKM commenting out because services don't know about this class + // throw new RemoteFileIOException(e); + } + return result; + } + + public IHostFile createFolder(IProgressMonitor monitor, String remoteParent, String folderName) throws SystemMessageException + { + IHostFile result = null; + try { + String fullPath = remoteParent + '/' + folderName; + fChannelSftp.mkdir(fullPath); + SftpATTRS attrs = fChannelSftp.stat(fullPath); + result = makeHostFile(remoteParent, folderName, attrs); + } catch (Exception e) { + e.printStackTrace(); + // DKM commenting out because services don't know about this class + //throw new RemoteFileIOException(e); + } + return result; + } + + public boolean delete(IProgressMonitor monitor, String remoteParent, String fileName) throws SystemMessageException + { + boolean ok=false; + try { + String fullPath = remoteParent + '/' + fileName; + SftpATTRS attrs = fChannelSftp.stat(fullPath); + if (attrs==null) { + //doesn't exist, nothing to do + } else if (attrs.isDir()) { + fChannelSftp.rmdir(fullPath); + } else { + fChannelSftp.rm(fullPath); + } + ok=true; + } catch (Exception e) { + e.printStackTrace(); + // DKM commenting out because services don't know about this class + //throw new RemoteFileIOException(e); + } + return ok; + } + + public boolean rename(IProgressMonitor monitor, String remoteParent, String oldName, String newName) throws SystemMessageException + { + boolean ok=false; + try { + String fullPathOld = remoteParent + '/' + oldName; + String fullPathNew = remoteParent + '/' + newName; + fChannelSftp.rename(fullPathOld, fullPathNew); + ok=true; + } catch (Exception e) { + e.printStackTrace(); + // DKM commenting out because services don't know about this class + //throw new RemoteFileIOException(e); + } + return ok; + } + + public boolean rename(IProgressMonitor monitor, String remoteParent, String oldName, String newName, IHostFile oldFile) throws SystemMessageException { + // TODO dont know how to update + return rename(monitor, remoteParent, oldName, newName); + } + + private boolean progressWorked(IProgressMonitor monitor, int work) { + boolean cancelRequested = false; + if (monitor!=null) { + monitor.worked(work); + cancelRequested = monitor.isCanceled(); + } + return cancelRequested; + } + + public int runCommand(IProgressMonitor monitor, String command) throws SystemMessageException + { + int result = -1; + if (monitor!=null) { + monitor.beginTask(command, 20); + } + Channel channel = null; + try { + channel=fSessionProvider.getSession().openChannel("exec"); //$NON-NLS-1$ + ((ChannelExec)channel).setCommand(command); + + //No user input + channel.setInputStream(null); + //TODO capture error output for exception + ((ChannelExec)channel).setErrStream(System.err); + InputStream in=channel.getInputStream(); + channel.connect(); + byte[] tmp=new byte[1024]; + while(!channel.isClosed()){ + if( progressWorked(monitor,1) ) { + break; + } + while(in.available()>0){ + int i=in.read(tmp, 0, 1024); + if(i<0)break; + //System.out.print(new String(tmp, 0, i)); + } + try{Thread.sleep(1000);}catch(Exception ee){} + } + result = channel.getExitStatus(); + } catch(Exception e) { + // DKM + // not visible to this plugin + // throw new RemoteFileIOException(e); + } finally { + if (monitor!=null) { + monitor.done(); + } + if (channel!=null) { + channel.disconnect(); + } + } + return result; + } + + public boolean move(IProgressMonitor monitor, String srcParent, String srcName, String tgtParent, String tgtName) throws SystemMessageException + { + // move is not supported by sftp directly. Use the ssh shell instead. + // TODO check if newer versions of sftp support move directly + // TODO Interpret some error messages like "command not found" (use ren instead of mv on windows) + String fullPathOld = srcParent + '/' + srcName; + String fullPathNew = tgtParent + '/' + tgtName; + //TODO quote pathes if necessary + int rv = runCommand(monitor, "mv "+fullPathOld+' '+fullPathNew); //$NON-NLS-1$ + return (rv==0); + } + + public boolean copy(IProgressMonitor monitor, String srcParent, String srcName, String tgtParent, String tgtName) throws SystemMessageException { + // move is not supported by sftp directly. Use the ssh shell instead. + // TODO check if newer versions of sftp support move directly + // TODO Interpret some error messages like "command not found" (use (x)copy instead of cp on windows) + String fullPathOld = srcParent + '/' + srcName; //$NON-NLS-1$ + String fullPathNew = tgtParent + '/' + tgtName; //$NON-NLS-1$ + //TODO quote pathes if necessary + int rv = runCommand(monitor, "cp "+fullPathOld+' '+fullPathNew); //$NON-NLS-1$ + return (rv==0); + } + + public boolean copyBatch(IProgressMonitor monitor, String[] srcParents, String[] srcNames, String tgtParent) throws SystemMessageException + { + boolean ok = true; + for (int i = 0; i < srcParents.length; i++) + { + ok = ok && copy(monitor, srcParents[i], srcNames[i], tgtParent, srcNames[i]); + } + return ok; + } + + public void initService(IProgressMonitor monitor) { + try + { + connect(); + } + catch (Exception e) + { + } + } + + public void uninitService(IProgressMonitor monitor) { + disconnect(); + } + + public boolean isCaseSensitive() { + //TODO find out whether remote is case sensitive or not + return true; + } + +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpHostFile.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpHostFile.java new file mode 100644 index 00000000000..6c25c3b7828 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/files/SftpHostFile.java @@ -0,0 +1,153 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from FTPHostFile. + ********************************************************************************/ + +package org.eclipse.rse.services.ssh.files; + +import java.io.File; + +import org.eclipse.rse.services.clientserver.archiveutils.ArchiveHandlerManager; +import org.eclipse.rse.services.files.IHostFile; + +public class SftpHostFile implements IHostFile { + + private String fName; + private String fParentPath; + private boolean fIsDirectory = false; + private boolean fIsRoot = false; + private boolean fIsArchive = false; + private boolean fExists = true; + private long fLastModified = 0; + private long fSize = 0; + private boolean fIsLink = false; + private String[] fExtended = null; + + //TODO just re-use or extend FTPHostFile instead of copying here? + public SftpHostFile(String parentPath, String name, boolean isDirectory, boolean isRoot, boolean isLink, long lastModified, long size) { + fParentPath = parentPath; + fName = name; + fIsDirectory = isDirectory; + fIsRoot = isRoot; + fLastModified = lastModified; + fSize = size; + fIsLink = isLink; + fIsArchive = internalIsArchive(); + } + + public String getName() { + return fName; + } + + public boolean isHidden() { + String name = getName(); + return name.charAt(0) == '.'; + } + + public String getParentPath() { + return fParentPath; + } + + public boolean isDirectory() { + return fIsDirectory; + } + + public boolean isFile() { + return !(fIsDirectory || fIsRoot || fIsLink); + } + + public boolean isRoot() { + return fIsRoot; + } + + public void setExists(boolean b) { + fExists = b; + } + + public boolean exists() { + return fExists; + } + + public String getAbsolutePath() { + if (isRoot()) { + return getName(); + } else { + StringBuffer path = new StringBuffer(getParentPath()); + if (!fParentPath.endsWith("/")) + { + path.append('/'); + } + path.append(getName()); + return path.toString(); + } + } + + public long getSize() { + return fSize; + } + + public long getModifiedDate() { + return fLastModified; + } + + public void renameTo(String newAbsolutePath) { + int i = newAbsolutePath.lastIndexOf("/"); + if (i == -1) { + fName = newAbsolutePath; + } + else { + fParentPath = newAbsolutePath.substring(0, i); + fName = newAbsolutePath.substring(i+1); + } + fIsArchive = internalIsArchive(); + } + + protected boolean internalIsArchive() { + return ArchiveHandlerManager.getInstance().isArchive(new File(getAbsolutePath())) + && !ArchiveHandlerManager.isVirtual(getAbsolutePath()); + } + + public boolean isArchive() { + return fIsArchive; + } + + public boolean isLink() { + return fIsLink; + } + + /** Extended data: name:value pairs */ + public void setExtendedData(String[] extended) { + fExtended = extended; + } + + public String[] getExtendedData() { + return fExtended; + } + + public String getClassification() { + //TODO: isExecutable(), shellscript vs. binary + String result; + if (isLink()) { + //TODO: read symbolic link target and its type to provide e.g. "symbolic link(directory):/export4/opt + result = "symbolic link"; //$NON-NLS-1$ + } else if (isFile()) { + result = "file"; //$NON-NLS-1$ + } else if (isDirectory()) { + result = "directory"; //$NON-NLS-1$ + } else { + result = "unknown"; //default-fallback //$NON-NLS-1$ + } + return result; + } +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshHostShell.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshHostShell.java new file mode 100644 index 00000000000..ec6b0edbe5a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshHostShell.java @@ -0,0 +1,87 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalHostShell. + ********************************************************************************/ + +package org.eclipse.rse.services.ssh.shell; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; + + +import org.eclipse.rse.services.shells.AbstractHostShell; +import org.eclipse.rse.services.shells.IHostShellOutputReader; +import org.eclipse.rse.services.ssh.ISshSessionProvider; + +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.Session; + +/** + * A Shell subsystem for SSH. + */ +public class SshHostShell extends AbstractHostShell { + + private ISshSessionProvider fSessionProvider; + private Channel fChannel; + private SshShellOutputReader fStdoutHandler; + private SshShellOutputReader fStderrHandler; + private PrintWriter fStdinHandler; + + public SshHostShell(ISshSessionProvider sessionProvider, String initialWorkingDirectory, String commandToRun, String encoding, String[] environment) { + try { + fSessionProvider = sessionProvider; + fChannel = fSessionProvider.getSession().openChannel("shell"); //$NON-NLS-1$ + + ////disable pty mode. This works in jsch-0.1.25 and later only. + ////By default, jsch always creates a vt100 connection sized + ////80x24 / 640x480 (dimensions can be changed). + ////I wonder whether jsch could give us a dumb terminal? + //if(fChannel instanceof ChannelShell) { + // ((ChannelShell)fChannel).setPty(false); + //} + + fStdoutHandler = new SshShellOutputReader(this, new BufferedReader(new InputStreamReader(fChannel.getInputStream())), false); + fStderrHandler = new SshShellOutputReader(this, null,true); + fStdinHandler = new PrintWriter(fChannel.getOutputStream()); + + fChannel.connect(); + } catch(Exception e) { + //TODO Forward exception to RSE properly + e.printStackTrace(); + } + } + + public boolean isActive() { + return !fChannel.isEOF(); + } + + public void writeToShell(String command) { + fStdinHandler.println(command); + fStdinHandler.flush(); + } + + public IHostShellOutputReader getStandardOutputReader() { + return fStdoutHandler; + } + + public IHostShellOutputReader getStandardErrorReader() { + return fStderrHandler; + } + + public void exit() { + fChannel.disconnect(); + } + +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellOutputReader.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellOutputReader.java new file mode 100644 index 00000000000..3c42c9eccfd --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellOutputReader.java @@ -0,0 +1,126 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalShellOutputReader. + * Martin Oberhuber (Wind River) - Added vt100 escape sequence ignoring. + ********************************************************************************/ + +package org.eclipse.rse.services.ssh.shell; + +import java.io.BufferedReader; +import java.io.IOException; + +import org.eclipse.rse.services.shells.AbstractHostShellOutputReader; +import org.eclipse.rse.services.shells.IHostShell; +import org.eclipse.rse.services.shells.IHostShellOutputReader; + +/** + * Listener to shell output. As io streams through, refresh events are sent out + * for the OutputChangeListener to respond to. + * VT100 terminal escape sequences are ignored. + */ +public class SshShellOutputReader extends AbstractHostShellOutputReader + implements IHostShellOutputReader { + + protected BufferedReader fReader; + + public SshShellOutputReader(IHostShell hostShell, BufferedReader reader, + boolean isErrorReader) { + super(hostShell, isErrorReader); + fReader = reader; + } + + protected Object internalReadLine() { + if (fReader == null) { + //Our workaround sets the stderr reader to null, so we never give any stderr output. + //TODO Check if ssh supports some method of having separate stdout and stderr streams + return null; + } + StringBuffer theLine = new StringBuffer(); + int ch; + int lastch = 0; + boolean done = false; + while (!done && !isFinished()) { + try { + ch = fReader.read(); + switch (ch) { + case -1: + if (theLine.length() == 0) // End of Reader + return null; + done = true; + break; + case 65535: + if (theLine.length() == 0) // Check why I keep getting this!!! + return null; + done = true; + break; + case 10: + done = true; // Newline + break; + case 9: + //TODO Count characters and insert as many as needed to do a real tab + theLine.append(" "); // Tab //$NON-NLS-1$ + break; + case 13: + break; // Carriage Return + default: + char tch = (char) ch; + if (!Character.isISOControl(tch)) { + theLine.append(tch); // Any other character + } else if (ch == 27) { + // Escape: ignore next char too + int nch = (char)fReader.read(); + if (nch == 91) { + //vt100 escape sequence: read until end-of-command (skip digits and semicolon) + //e.g. \x1b;13;m --> ignore the entire command, including the trailing m + do { + nch = fReader.read(); + } while (Character.isDigit((char)nch) || nch == ';'); + } + } + } + + boolean ready = fReader.ready(); + //TODO Get rid of this to support UNIX and Mac? -- It appears that + //due to vt100 emulation we get CRLF even for UNIX connections. + if (ch == 10 && lastch == 13) { + return theLine.toString(); + } + lastch = ch; + + // Check to see if the BufferedReader is still ready which means + // there are more characters + // in the Buffer...If not, then we assume it is waiting for + // input. + if (!ready) { + // wait to make sure + try { + Thread.sleep(_waitIncrement); + } catch (InterruptedException e) { + } + if (!fReader.ready()) { + if (done) { + return theLine.toString().trim(); + } else { + done = true; + } + } + } + } catch (IOException e) { + return null; + } + } + return theLine.toString(); + } + +} diff --git a/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellService.java b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellService.java new file mode 100644 index 00000000000..5eaec06130f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.ssh/src/org/eclipse/rse/services/ssh/shell/SshShellService.java @@ -0,0 +1,96 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalShellService. + ********************************************************************************/ + +package org.eclipse.rse.services.ssh.shell; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.shells.IHostShell; +import org.eclipse.rse.services.shells.IShellService; +import org.eclipse.rse.services.ssh.ISshService; +import org.eclipse.rse.services.ssh.ISshSessionProvider; + +import com.jcraft.jsch.Session; + +/** + * A Shell Services for ssh. + * Adapted from LocalShellService. + */ +public class SshShellService implements ISshService, IShellService { + + private static final String SHELL_INVOCATION = ">"; + private ISshSessionProvider fSessionProvider; + + public SshShellService(ISshSessionProvider sessionProvider) { + fSessionProvider = sessionProvider; + } + + //TODO abstract base class should handle default encodings + public IHostShell launchShell(IProgressMonitor monitor, + String initialWorkingDirectory, String[] environment) { + String defaultEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$ + return launchShell(monitor, initialWorkingDirectory, defaultEncoding, environment); + } + + public IHostShell launchShell(IProgressMonitor monitor, + String initialWorkingDirectory, String encoding, + String[] environment) { + SshHostShell hostShell = new SshHostShell(fSessionProvider, initialWorkingDirectory, SHELL_INVOCATION, encoding, environment); + return hostShell; + } + + //TODO abstract base class should handle default encodings + public IHostShell runCommand(IProgressMonitor monitor, + String initialWorkingDirectory, String command, String[] environment) { + String defaultEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$ + return runCommand(monitor, initialWorkingDirectory, command, defaultEncoding, environment); + } + + //TODO command is ignored by SshHostShell for now (just like DStoreHostShell). + public IHostShell runCommand(IProgressMonitor monitor, + String initialWorkingDirectory, String command, String encoding, + String[] environment) { + SshHostShell hostShell = new SshHostShell(fSessionProvider, initialWorkingDirectory, command, encoding, environment); + return hostShell; + } + + public String[] getHostEnvironment() { + //TODO getHostEnvironment is not yet implemented for ssh (needs running remote command and parsing) + return new String[0]; + } + + public String getName() { + //TODO Externalize Strings + return "SSH Shell Service"; + } + + public String getDescription() { + return "SSH Shell Service Description"; + } + + public void initService(IProgressMonitor monitor) { + // nothing to do + } + + public void uninitService(IProgressMonitor monitor) { + // nothing to do + } + + public SystemMessage getMessage(String messageID) { + return null; + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.classpath b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.classpath new file mode 100644 index 00000000000..751c8f2e504 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.project b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.project new file mode 100644 index 00000000000..bffdbdcd653 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.subsystems.files.ssh + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..aa1306e3e46 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Ssh Plug-in +Bundle-SymbolicName: org.eclipse.rse.subsystems.files.ssh; singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.rse.subsystems.files.ssh.Activator +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.rse.services, + org.eclipse.rse.connectorservice.ssh, + org.eclipse.rse.services.ssh, + org.eclipse.rse.core, + org.eclipse.rse.subsystems.files.core, + com.jcraft.jsch, + org.eclipse.rse.ui +Eclipse-LazyStart: true +Export-Package: org.eclipse.rse.subsystems.files.ssh diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/build.properties b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfiles_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfiles_obj.gif new file mode 100644 index 00000000000..874c9926215 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfiles_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfileslive_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfileslive_obj.gif new file mode 100644 index 00000000000..885b8a69e39 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/icons/full/obj16/systemfileslive_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.properties b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.properties new file mode 100644 index 00000000000..76d03d380f9 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.properties @@ -0,0 +1,15 @@ +################################################################################ +# Copyright (c) 2006 Wind River Systems, 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: +# Martin Oberhuber - initial API and implementation +################################################################################ + +plugin.name = Ssh Files Plugin + +SshFileSubsystemName=Sftp Files +SshFileSubsystemDescription=Show Sftp Files on remote host. diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.xml b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.xml new file mode 100644 index 00000000000..04fabb1967f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/plugin.xml @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/Activator.java b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/Activator.java new file mode 100644 index 00000000000..a2829b360c6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/Activator.java @@ -0,0 +1,61 @@ +package org.eclipse.rse.subsystems.files.ssh; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.rse.subsystems.files.ssh"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileAdapter.java b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileAdapter.java new file mode 100644 index 00000000000..214fd9d9969 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileAdapter.java @@ -0,0 +1,63 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from FTPFileAdapter. + ********************************************************************************/ + +package org.eclipse.rse.subsystems.files.ssh; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.rse.services.ssh.files.SftpHostFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext; +import org.eclipse.rse.ui.ISystemPreferencesConstants; +import org.eclipse.rse.ui.RSEUIPlugin; + +public class SftpFileAdapter implements IHostFileToRemoteFileAdapter { + + public IRemoteFile[] convertToRemoteFiles(FileServiceSubSystem ss, IRemoteFileContext context, IRemoteFile parent, IHostFile[] nodes) { + boolean showHidden = RSEUIPlugin.getDefault().getPreferenceStore().getBoolean(ISystemPreferencesConstants.SHOWHIDDEN); + + List results = new ArrayList(); + for (int i = 0; i < nodes.length; i++) { + SftpHostFile node = (SftpHostFile)nodes[i]; + if (showHidden || !node.isHidden()) { + IRemoteFile remoteFile = new SftpRemoteFile(ss, context, parent, node); + results.add(remoteFile); + ss.cacheRemoteFile(remoteFile); + } + } + return (IRemoteFile[])results.toArray(new IRemoteFile[results.size()]); + } + + public IRemoteFile convertToRemoteFile(FileServiceSubSystem ss, IRemoteFileContext context, IRemoteFile parent, String name, boolean isDirectory, boolean isRoot) { + return null; + } + + public IRemoteFile convertToRemoteFile(FileServiceSubSystem ss, IRemoteFileContext context, IRemoteFile parent, IHostFile node) { + IRemoteFile file = new SftpRemoteFile(ss, context, parent, (SftpHostFile)node); + ss.cacheRemoteFile(file); + return file; + } + + public IRemoteFile convertToRemoteFile(FileServiceSubSystem ss, IRemoteFileContext context, IRemoteFile parent, Object object) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileSubSystemConfiguration.java b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileSubSystemConfiguration.java new file mode 100644 index 00000000000..2db9495fff3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpFileSubSystemConfiguration.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems, 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: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.subsystems.files.ssh; + +import org.eclipse.rse.connectorservice.ssh.SshConnectorService; +import org.eclipse.rse.connectorservice.ssh.SshConnectorServiceManager; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.subsystems.files.core.ILanguageUtilityFactory; +import org.eclipse.rse.model.IHost; +import org.eclipse.rse.services.clientserver.SystemSearchString; +import org.eclipse.rse.services.files.IFileService; +import org.eclipse.rse.services.search.IHostSearchResultConfiguration; +import org.eclipse.rse.services.search.IHostSearchResultSet; +import org.eclipse.rse.services.search.ISearchService; +import org.eclipse.rse.services.ssh.ISshService; +import org.eclipse.rse.services.ssh.ISshSessionProvider; +import org.eclipse.rse.services.ssh.files.SftpFileService; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystemConfiguration; +import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; + +import com.jcraft.jsch.Session; + +public class SftpFileSubSystemConfiguration extends FileServiceSubSystemConfiguration { + + protected IHostFileToRemoteFileAdapter _hostFileAdapter; + + public SftpFileSubSystemConfiguration() { + super(); + setIsUnixStyle(true); + } + + public boolean isFactoryFor(Class subSystemType) { + boolean isFor = FileServiceSubSystem.class.equals(subSystemType); + return isFor; + } + + public boolean supportsArchiveManagement() { + return false; + } + + public ISubSystem createSubSystemInternal(IHost host) { + SshConnectorService connectorService = (SshConnectorService)getConnectorService(host); + ISubSystem subsys = new FileServiceSubSystem(host, connectorService, getFileService(host), getHostFileAdapter(), getSearchService(host)); + return subsys; + } + + public boolean supportsFileTypes() { + return false; + } + + public boolean supportsSearch() { + return false; + } + + public boolean supportsEnvironmentVariablesPropertyPage() { + return false; + } + + public boolean supportsFilters() { + return true; + } + + public IConnectorService getConnectorService(IHost host) { + return SshConnectorServiceManager.getInstance().getConnectorService(host, getServiceImplType()); + } + + public void setConnectorService(IHost host, IConnectorService connectorService) { + SshConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService); + } + + public IFileService createFileService(IHost host) { + SshConnectorService connectorService = (SshConnectorService)getConnectorService(host); + //return connectorService.getFileService(); + //TODO We have to get the file service from the connector service in order to make + //sure the connector service can connect it when required. It might be better to + //create a new instance here, and have it connect lazily on demand instead. + //In fact, due to ssh timeouts, it might be necessary that we can re-connect + //on demand on any operation anyway. + return new SftpFileService((ISshSessionProvider)connectorService); + } + + public ISearchService createSearchService(IHost host) { + // no search service supported for ssh/sftp at moment + return null; + } + + public IHostFileToRemoteFileAdapter getHostFileAdapter() { + if (_hostFileAdapter == null) { + _hostFileAdapter = new SftpFileAdapter(); + } + return _hostFileAdapter; + } + + public IHostSearchResultConfiguration createSearchConfiguration(IHost host, IHostSearchResultSet resultSet, Object searchTarget, SystemSearchString searchString) { + return null; + } + + public ILanguageUtilityFactory getLanguageUtilityFactory(IRemoteFileSubSystem ss) { + return null; + } + + public Class getServiceImplType() { + return ISshService.class; + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpRemoteFile.java b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpRemoteFile.java new file mode 100644 index 00000000000..6a5c308bee2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.files.ssh/src/org/eclipse/rse/subsystems/files/ssh/SftpRemoteFile.java @@ -0,0 +1,47 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from FTPRemoteFile. + ********************************************************************************/ + +package org.eclipse.rse.subsystems.files.ssh; + +import org.eclipse.rse.services.ssh.files.SftpHostFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.AbstractRemoteFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext; + +public class SftpRemoteFile extends AbstractRemoteFile { + + public SftpRemoteFile(FileServiceSubSystem ss, IRemoteFileContext context, IRemoteFile parent, SftpHostFile hostFile) { + super(ss, context, parent, hostFile); + } + + public SftpHostFile getSftpHostFile() { + return (SftpHostFile)getHostFile(); + } + + public boolean isVirtual() { + return false; + } + + public String getCanonicalPath() { + return getAbsolutePath(); + } + + public String getClassification() { + return getSftpHostFile().getClassification(); + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.classpath b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.classpath new file mode 100644 index 00000000000..751c8f2e504 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.project b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.project new file mode 100644 index 00000000000..8762a137e8d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.subsystems.shells.ssh + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..1c67ac0c02a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Ssh Plug-in +Bundle-SymbolicName: org.eclipse.rse.subsystems.shells.ssh; singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.rse.subsystems.shells.ssh.Activator +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.rse.services, + org.eclipse.rse.connectorservice.ssh, + org.eclipse.rse.services.ssh, + org.eclipse.rse.ui, + org.eclipse.rse.core, + org.eclipse.rse.subsystems.shells.core, + com.jcraft.jsch +Eclipse-LazyStart: true +Export-Package: org.eclipse.rse.subsystems.shells.ssh diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/build.properties b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommands_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommands_obj.gif new file mode 100644 index 00000000000..061b6e226a9 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommands_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommandslive_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommandslive_obj.gif new file mode 100644 index 00000000000..3faca447424 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/icons/full/obj16/systemcommandslive_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.properties b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.properties new file mode 100644 index 00000000000..a882b3df9b0 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.properties @@ -0,0 +1,17 @@ +################################################################################ +# Copyright (c) 2006 Wind River Systems, 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: +# Martin Oberhuber - initial API and implementation +################################################################################ + +plugin.name = Ssh Shells Plugin + + +SshShellSubsystemName=Shells +SshShellSubsystemDescription=This configuration allows you to work with shells and commands on remote systems using the Secure Shell (ssh) protocol. + diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.xml b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.xml new file mode 100644 index 00000000000..45aa5f0861a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/plugin.xml @@ -0,0 +1,29 @@ + + + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/Activator.java b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/Activator.java new file mode 100644 index 00000000000..fe10bfb5c70 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/Activator.java @@ -0,0 +1,61 @@ +package org.eclipse.rse.subsystems.shells.ssh; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.rse.subsystems.shells.ssh"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/SshShellSubSystemConfiguration.java b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/SshShellSubSystemConfiguration.java new file mode 100644 index 00000000000..294339b41d7 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.ssh/src/org/eclipse/rse/subsystems/shells/ssh/SshShellSubSystemConfiguration.java @@ -0,0 +1,82 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted template for ssh service. + ********************************************************************************/ + +package org.eclipse.rse.subsystems.shells.ssh; + +import org.eclipse.rse.connectorservice.ssh.SshConnectorService; +import org.eclipse.rse.connectorservice.ssh.SshConnectorServiceManager; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.model.Host; +import org.eclipse.rse.model.IHost; +import org.eclipse.rse.services.shells.IShellService; +import org.eclipse.rse.services.ssh.ISshService; +import org.eclipse.rse.services.ssh.ISshSessionProvider; +import org.eclipse.rse.services.ssh.shell.SshShellService; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystem; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystemConfiguration; + +public class SshShellSubSystemConfiguration extends + ShellServiceSubSystemConfiguration { + + public SshShellSubSystemConfiguration() { + super(); + } + + public boolean supportsCommands() { + //TODO support commands in SshShellService.runCommand() + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#isFactoryFor(java.lang.Class) + */ + public boolean isFactoryFor(Class subSystemType) { + boolean isFor = ShellServiceSubSystem.class.equals(subSystemType); + return isFor; + } + + /** + * Instantiate and return an instance of OUR subystem. + * Do not populate it yet though! + * @see org.eclipse.rse.core.subsystems.impl.SubSystemFactoryImpl#createSubSystemInternal(Host) + */ + public ISubSystem createSubSystemInternal(IHost host) + { + SshConnectorService connectorService = (SshConnectorService)getConnectorService(host); + ISubSystem subsys = new ShellServiceSubSystem(host, connectorService, createShellService(host)); + return subsys; + } + + public IShellService createShellService(IHost host) { + SshConnectorService cserv = (SshConnectorService)getConnectorService(host); + return new SshShellService((ISshSessionProvider)cserv); + } + + public IConnectorService getConnectorService(IHost host) { + return SshConnectorServiceManager.getInstance().getConnectorService(host, ISshService.class); + } + + public void setConnectorService(IHost host, + IConnectorService connectorService) { + SshConnectorServiceManager.getInstance().setConnectorService(host, ISshService.class, connectorService); + } + + public Class getServiceImplType() { + return ISshService.class; + } + +}