diff options
9 files changed, 1093 insertions, 0 deletions
diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Method.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Method.java new file mode 100644 index 000000000..f29641fd8 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Method.java @@ -0,0 +1,26 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; +import org.eclipse.team.internal.ccvs.core.IConnectionMethod; +import org.eclipse.team.internal.ccvs.core.IServerConnection; + +public class CVSSSH2Method implements IConnectionMethod { + public String getName() { return "extssh2"; } + public IServerConnection createConnection(ICVSRepositoryLocation root, + String password) { + return new CVSSSH2ServerConnection(root, password); + } + public void disconnect(ICVSRepositoryLocation location) { + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Plugin.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Plugin.java new file mode 100644 index 000000000..876d9e593 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2Plugin.java @@ -0,0 +1,52 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jface.preference.IPreferenceStore; + +public class CVSSSH2Plugin extends AbstractUIPlugin{ + + public static String ID="org.eclipse.team.cvs.ssh2"; + private static CVSSSH2Plugin plugin; + + public CVSSSH2Plugin(IPluginDescriptor d){ + super(d); + plugin=this; + } + + public static CVSSSH2Plugin getPlugin(){ return plugin; } + + public void shutdown() throws org.eclipse.core.runtime.CoreException{ + JSchSession.shutdown(); + super.shutdown(); + } + + public static CVSSSH2Plugin getDefault() { + return plugin; + } + + public static IWorkspace getWorkspace() { + return ResourcesPlugin.getWorkspace(); + } + + protected void initializeDefaultPreferences(IPreferenceStore store) { + CVSSSH2PreferencePage.initDefaults(store); + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2PreferencePage.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2PreferencePage.java new file mode 100644 index 000000000..24b947ce3 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2PreferencePage.java @@ -0,0 +1,221 @@ +/* -*-mode:java; c-basic-offset:2; -*- */
+/**********************************************************************
+Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+ Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation.
+**********************************************************************/
+package org.eclipse.team.cvs.ssh2;
+
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.DirectoryFieldEditor;
+import org.eclipse.jface.preference.ColorFieldEditor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class CVSSSH2PreferencePage extends FieldEditorPreferencePage
+ implements IWorkbenchPreferencePage {
+
+ public static String KEY_PROXY="CVSSSH2PreferencePage.PROXY";
+ public static String KEY_PROXY_TYPE="CVSSSH2PreferencePage.PROXY_TYPE";
+ public static String KEY_PROXY_HOST="CVSSSH2PreferencePage.PROXY_HOST";
+ public static String KEY_PROXY_PORT="CVSSSH2PreferencePage.PROXY_PORT";
+ public static String KEY_SSH2HOME="CVSSSH2PreferencePage.SSH2HOME";
+
+ static String SOCKS5="SOCKS5";
+ static String HTTP="HTTP";
+ private static String HTTP_DEFAULT_PORT="80";
+ private static String SOCKS5_DEFAULT_PORT="1080";
+
+ private DirectoryFieldEditor ssh2homeEditor;
+
+ private Label proxyTypeLabel;
+ private Label proxyHostLabel;
+ private Label proxyPortLabel;
+ private Combo proxyTypeCombo;
+ private Text proxyHostText;
+ private Text proxyPortText;
+ private Button enableProxy;
+ private boolean useProxy;
+
+ public CVSSSH2PreferencePage() {
+ super(GRID);
+ IPreferenceStore store=CVSSSH2Plugin.getDefault().getPreferenceStore();
+ setPreferenceStore(store);
+ setDescription("General CVSSSH2 Settings:");
+ }
+
+ protected void createFieldEditors() {
+ ssh2homeEditor=
+ new DirectoryFieldEditor(KEY_SSH2HOME,
+ "SSH2 Home",
+ getFieldEditorParent());
+ addField(ssh2homeEditor);
+
+ createSpacer(getFieldEditorParent(), 3);
+
+ createProxy(getFieldEditorParent(), 3);
+ }
+
+ private void updateControls() {
+ boolean enable=enableProxy.getSelection();
+ proxyTypeLabel.setEnabled(enable);
+ proxyTypeCombo.setEnabled(enable);
+ proxyPortLabel.setEnabled(enable);
+ proxyPortText.setEnabled(enable);
+ proxyHostLabel.setEnabled(enable);
+ proxyHostText.setEnabled(enable);
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+ protected void initialize() {
+ super.initialize();
+ initControls();
+ }
+
+ public static void initDefaults(IPreferenceStore store) {
+ setDefault(store, KEY_SSH2HOME, JSchSession.default_ssh_home);
+ setDefault(store, KEY_PROXY_TYPE, HTTP);
+ setDefault(store, KEY_PROXY_PORT, HTTP_DEFAULT_PORT);
+ }
+
+ private static void setDefault(IPreferenceStore store, String key, String value){
+ store.setDefault(key, value);
+ if(store.getString(key).length()==0)
+ store.setValue(key, value);
+ }
+
+ private void initControls(){
+ IPreferenceStore store=CVSSSH2Plugin.getDefault().getPreferenceStore();
+ useProxy=store.getString(KEY_PROXY).equals("true");
+ enableProxy.setSelection(useProxy);
+ proxyHostText.setText(store.getString(KEY_PROXY_HOST));
+ proxyPortText.setText(store.getString(KEY_PROXY_PORT));
+ proxyTypeCombo.select(store.getString(KEY_PROXY_TYPE).equals(HTTP)?0:1);
+ updateControls();
+ }
+ protected void createProxy(Composite composite, int columnSpan) {
+ Group group=new Group(composite, SWT.NONE);
+ group.setText("Proxy settings");
+ GridLayout layout=new GridLayout();
+ layout.numColumns=2;
+ group.setLayout(layout);
+ GridData gd=new GridData();
+ gd.horizontalSpan=columnSpan;
+ gd.horizontalAlignment=GridData.FILL;
+ group.setLayoutData(gd);
+ group.setFont(composite.getFont());
+
+ enableProxy=new Button(group, SWT.CHECK);
+ enableProxy.setText("Enable proxy connection");
+ gd=new GridData();
+ gd.horizontalSpan=2;
+ enableProxy.setLayoutData(gd);
+
+ proxyTypeLabel=new Label(group, SWT.NONE);
+ proxyTypeLabel.setText("Proxy type");
+ proxyTypeCombo=new Combo(group, SWT.READ_ONLY);
+ proxyTypeCombo.setFont(group.getFont());
+ gd=new GridData(GridData.FILL_HORIZONTAL);
+ proxyTypeCombo.setLayoutData(gd);
+ proxyTypeCombo.addModifyListener(new ModifyListener () {
+ public void modifyText(ModifyEvent e){
+ if(proxyPortText==null) return;
+ Combo combo=(Combo)(e.getSource());
+ String foo=combo.getText();
+ if(foo.equals(HTTP)){
+ proxyPortText.setText(HTTP_DEFAULT_PORT);
+ }
+ else if(foo.equals(SOCKS5)){
+ proxyPortText.setText(SOCKS5_DEFAULT_PORT);
+ }
+ }
+ });
+ proxyTypeCombo.add(HTTP);
+ proxyTypeCombo.add(SOCKS5);
+ proxyTypeCombo.select(0);
+
+ proxyHostLabel=new Label(group, SWT.NONE);
+ proxyHostLabel.setText("Proxy host address");
+
+ proxyHostText=new Text(group, SWT.SINGLE | SWT.BORDER);
+ proxyHostText.setFont(group.getFont());
+ gd=new GridData(GridData.FILL_HORIZONTAL);
+ proxyHostText.setLayoutData(gd);
+
+ proxyPortLabel=new Label(group, SWT.NONE);
+ proxyPortLabel.setText("Proxy host port");
+
+ proxyPortText=new Text(group, SWT.SINGLE | SWT.BORDER);
+ proxyPortText.setFont(group.getFont());
+ gd=new GridData(GridData.FILL_HORIZONTAL);
+ proxyPortText.setLayoutData(gd);
+
+ // performDefaults();
+
+ enableProxy.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ updateControls();
+ }
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ }
+
+ public boolean performOk() {
+ boolean result=super.performOk();
+ if(result){
+ IPreferenceStore store=CVSSSH2Plugin.getDefault().getPreferenceStore();
+ store.setValue(KEY_PROXY, enableProxy.getSelection());
+ store.setValue(KEY_PROXY_TYPE, proxyTypeCombo.getText());
+ store.setValue(KEY_PROXY_HOST, proxyHostText.getText());
+ store.setValue(KEY_PROXY_PORT, proxyPortText.getText());
+ }
+ CVSSSH2Plugin.getDefault().savePluginPreferences();
+ return result;
+ }
+
+ public void performApply() {
+ super.performApply();
+ IPreferenceStore store=CVSSSH2Plugin.getDefault().getPreferenceStore();
+ store.setValue(KEY_PROXY, enableProxy.getSelection());
+ store.setValue(KEY_PROXY_TYPE, proxyTypeCombo.getText());
+ store.setValue(KEY_PROXY_HOST, proxyHostText.getText());
+ store.setValue(KEY_PROXY_PORT, proxyPortText.getText());
+ }
+
+ protected void performDefaults(){
+ super.performDefaults();
+ enableProxy.setSelection(false);
+ proxyHostText.setText("");
+ proxyPortText.setText(HTTP_DEFAULT_PORT);
+ proxyTypeCombo.select(0);
+ updateControls();
+ }
+
+ protected void createSpacer(Composite composite, int columnSpan) {
+ Label label=new Label(composite, SWT.NONE);
+ GridData gd=new GridData();
+ gd.horizontalSpan=columnSpan;
+ label.setLayoutData(gd);
+ }
+}
diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2ServerConnection.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2ServerConnection.java new file mode 100644 index 000000000..cec941c1c --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/CVSSSH2ServerConnection.java @@ -0,0 +1,100 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; +import org.eclipse.team.internal.ccvs.core.IServerConnection; +import org.eclipse.team.internal.ccvs.core.connection.CVSAuthenticationException; + +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import com.jcraft.jsch.*; + +public class CVSSSH2ServerConnection implements IServerConnection { + + private static final String COMMAND="cvs server"; + + private ICVSRepositoryLocation location; + private String password; + + private InputStream inputStream; + private OutputStream outputStream; + + private Session session; + private Channel channel; + + protected CVSSSH2ServerConnection(ICVSRepositoryLocation location, + String password) { + this.location=location; + this.password=password; + } + + public void close() throws IOException { + if(channel!=null) + channel.disconnect(); + } + + public InputStream getInputStream() { return inputStream; } + public OutputStream getOutputStream() { return outputStream; } + + public void open(IProgressMonitor monitor) throws IOException, + CVSAuthenticationException { + try{ + String hostname=location.getHost(); + String username=location.getUsername(); + int port=location.getPort(); + if(port==ICVSRepositoryLocation.USE_DEFAULT_PORT) + port=0; + + int retry=1; + OutputStream channel_out; + InputStream channel_in; + + while(true){ + session=JSchSession.getSession(username, password, hostname, port); + channel=session.openChannel("exec"); + ((ChannelExec)channel).setCommand(COMMAND); + + channel_out=channel.getOutputStream(); + channel_in=channel.getInputStream(); + + try{ channel.connect(); } + catch(JSchException ee){ + if(!session.isConnected()){ + //System.out.println("sesssion is down"); + //channel.disconnect(); + retry--; + if(retry<0){ + throw new CVSAuthenticationException("session is down"); + } + continue; + } + throw ee; + } + break; + } + + inputStream=channel_in; + outputStream=channel_out; + } + catch(JSchException e){ + //e.printStackTrace(); + throw new CVSAuthenticationException(e.toString()); + } + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/JSchSession.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/JSchSession.java new file mode 100644 index 000000000..c0de27135 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/JSchSession.java @@ -0,0 +1,225 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import java.util.Enumeration; +import java.io.File; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.MessageBox; + +import com.jcraft.jsch.*; + +class JSchSession{ + private static final int SSH_DEFAULT_PORT=22; + private static JSch jsch; + private static java.util.Hashtable pool=new java.util.Hashtable(); + + static String default_ssh_home=null; + static { + default_ssh_home=System.getProperty("user.home"); + if(default_ssh_home!=null){ + default_ssh_home=default_ssh_home+java.io.File.separator+".ssh"; + } + } + + private static String current_ssh_home=null; + + static Session getSession(String username, String password, + String hostname, int port) throws JSchException{ + if(port==0) port=SSH_DEFAULT_PORT; + if(jsch==null){ + jsch=new JSch(); + } + + IPreferenceStore store=CVSSSH2Plugin.getDefault().getPreferenceStore(); + String ssh_home=store.getString(CVSSSH2PreferencePage.KEY_SSH2HOME); + + if(current_ssh_home==null || + !current_ssh_home.equals(ssh_home)){ + current_ssh_home=ssh_home; + if(ssh_home.length()==0) + ssh_home=default_ssh_home; + + try{ + java.io.File file; + file=new java.io.File(ssh_home, "id_dsa"); + if(file.exists()) jsch.addIdentity(file.getPath()); + file=new java.io.File(ssh_home, "id_rsa"); + if(file.exists()) jsch.addIdentity(file.getPath()); + file=new java.io.File(ssh_home, "known_hosts"); + jsch.setKnownHosts(file.getPath()); + } + catch(Exception e){ + } + } + + String key=username+"@"+hostname+":"+port; + + try{ + Session session=(Session)pool.get(key); + if(session!=null && !session.isConnected()){ + pool.remove(key); + session=null; + } + + if(session==null){ + session=jsch.getSession(username, hostname, port); + + boolean useProxy=store.getString(CVSSSH2PreferencePage.KEY_PROXY).equals("true"); + if(useProxy){ + String _type=store.getString(CVSSSH2PreferencePage.KEY_PROXY_TYPE); + String _host=store.getString(CVSSSH2PreferencePage.KEY_PROXY_HOST); + String _port=store.getString(CVSSSH2PreferencePage.KEY_PROXY_PORT); + + Proxy proxy=null; + String proxyhost=_host+":"+_port; + if(_type.equals(CVSSSH2PreferencePage.HTTP)){ + proxy=new ProxyHTTP(proxyhost); + } + else if(_type.equals(CVSSSH2PreferencePage.SOCKS5)){ + proxy=new ProxySOCKS5(proxyhost); + } + else{ + proxy=null; + } + if(proxy!=null){ + session.setProxy(proxy); + } + } + + session.setPassword(password); + + UserInfo ui=new MyUserInfo(username); + session.setUserInfo(ui); + session.connect(); + pool.put(key, session); + } + return session; + } + catch(JSchException e){ + //e.printStackTrace(); + pool.remove(key); + throw e; + } + } + + private static class MyUserInfo implements UserInfo{ + private String username; + private String password; + private String passphrase; + MyUserInfo(String username){ + this.username=username; + } + public String getPassword(){ return password; } + public String getPassphrase(){ return passphrase; } + public boolean promptYesNo(String str){ + YesNoPrompt prompt=new YesNoPrompt(str); + Display.getDefault().syncExec(prompt); + return prompt.getResult()==SWT.YES; + } + public boolean promptPassphrase(String message){ + PassphrasePrompt prompt=new PassphrasePrompt(message); + Display.getDefault().syncExec(prompt); + String _passphrase=prompt.getPassphrase(); + if(_passphrase!=null)passphrase=_passphrase; + return _passphrase!=null; + } + public boolean promptPassword(String message){ + PasswordPrompt prompt=new PasswordPrompt(message); + Display.getDefault().syncExec(prompt); + String _password=prompt.getPassword(); + if(_password!=null)password=_password; + return _password!=null; + } + public void showMessage(final String foo){ + final Display display=Display.getCurrent(); + display.syncExec(new Runnable(){ + public void run(){ + Shell shell=new Shell(display); + MessageBox box=new MessageBox(shell,SWT.OK); + box.setMessage(foo); + box.open(); + shell.dispose(); + } + }); + } + + private class YesNoPrompt implements Runnable{ + private String prompt; + private int result; + YesNoPrompt(String prompt){ + this.prompt=prompt; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + MessageBox box=new MessageBox(shell,SWT.YES|SWT.NO); + box.setMessage(prompt); + result=box.open(); + shell.dispose(); + } + public int getResult(){ return result; } + } + private class PasswordPrompt implements Runnable{ + private String message; + private String password; + PasswordPrompt(String message){ + this.message=message; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + PasswordDialog dialog=new PasswordDialog(shell, message); + dialog.open(); + shell.dispose(); + password=dialog.getPassword(); + } + public String getPassword(){ + return password; + } + } + private class PassphrasePrompt implements Runnable{ + private String message; + private String passphrase; + PassphrasePrompt(String message){ + this.message=message; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + PassphraseDialog dialog=new PassphraseDialog(shell, message); + dialog.open(); + shell.dispose(); + passphrase=dialog.getPassphrase(); + } + public String getPassphrase(){ + return passphrase; + } + } + } + + static void shutdown(){ + if(jsch!=null && pool.size()>0){ + for(Enumeration e=pool.elements(); e.hasMoreElements();){ + Session session=(Session)(e.nextElement()); + try{ session.disconnect(); } + catch(Exception ee){} + } + pool.clear(); + } + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2Method.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2Method.java new file mode 100644 index 000000000..2ba526e70 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2Method.java @@ -0,0 +1,26 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; +import org.eclipse.team.internal.ccvs.core.IConnectionMethod; +import org.eclipse.team.internal.ccvs.core.IServerConnection; + +public class PServerSSH2Method implements IConnectionMethod { + public String getName() { return "pserverssh2"; } + public IServerConnection createConnection(ICVSRepositoryLocation root, + String password) { + return new PServerSSH2ServerConnection(root, password); + } + public void disconnect(ICVSRepositoryLocation location) { + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2ServerConnection.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2ServerConnection.java new file mode 100644 index 000000000..89f4737e1 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PServerSSH2ServerConnection.java @@ -0,0 +1,246 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.util.Properties; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; +import org.eclipse.team.internal.ccvs.core.IServerConnection; +import org.eclipse.team.internal.ccvs.core.connection.CVSAuthenticationException; + +import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; +import org.eclipse.team.internal.ccvs.core.IConnectionMethod; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.MessageBox; + +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import com.jcraft.jsch.*; + +public class PServerSSH2ServerConnection implements IServerConnection { + + private ICVSRepositoryLocation location; + private String password; + + private Session session; + private Channel channel; + + private static int localport=2402; + + private IServerConnection psc=null; + + protected PServerSSH2ServerConnection(ICVSRepositoryLocation location, + String password) { + this.location=location; + this.password=password; + } + + public void close() throws IOException { + psc.close(); + } + + public InputStream getInputStream() { return psc.getInputStream(); } + public OutputStream getOutputStream() { return psc.getOutputStream(); } + + public void open(IProgressMonitor monitor) throws IOException, + CVSAuthenticationException { + String cvs_root=location.getRootDirectory(); + int cvs_port=location.getPort(); + if(cvs_port==0) cvs_port=2401; + String cvs_host=location.getHost(); + String ssh_host=cvs_host; + String ssh_user=location.getUsername(); + + String host=cvs_host; + if(host.indexOf('@')!=-1){ + cvs_host=host.substring(host.lastIndexOf('@')+1); + host=host.substring(0, host.lastIndexOf('@')); + if(host.indexOf('@')!=-1){ + ssh_host=host.substring(host.lastIndexOf('@')+1); + if(ssh_host.length()==0)ssh_host=cvs_host; + ssh_user=host.substring(0, host.lastIndexOf('@')); + } + else{ + ssh_host=host; + } + } + + int lport=cvs_port; + String rhost=(cvs_host.equals(ssh_host) ? "localhost" : cvs_host); + int rport=cvs_port; + + // ssh -L lport:rhost:rport ssh_user@ssh_host + int retry=1; + while(true){ + try{ + session=JSchSession.getSession(ssh_user, "", ssh_host, 0); + String[] list=session.getPortForwardingL(); + String name=":"+rhost+":"+rport; + boolean done=false; + for(int i=0; i<list.length; i++){ + if(list[i].endsWith(name)) { + try{ + String foo=list[i].substring(0, list[i].indexOf(':')); + lport=Integer.parseInt(foo); + } + catch(Exception ee){ + } + done=true; + break; + } + } + if(!done){ + lport=localport++; + session.setPortForwardingL(lport, rhost, rport); + } + } + catch(JSchException ee){ + if(!session.isConnected()){ + //System.out.println("sesssion is down"); + retry--; + if(retry<0){ + throw new CVSAuthenticationException(ee.toString()); + } + continue; + } + throw new CVSAuthenticationException(ee.toString()); + } + break; + } + + // CVSROOT=":pserver:localhost:"+lport+""cvs_root + try{ + Properties prop=new Properties(); + prop.put("connection", "pserver"); + prop.put("user", location.getUsername()); + prop.put("password", password); + prop.put("host", "localhost"); + prop.put("port", Integer.toString(lport)); + prop.put("root", cvs_root); + + CVSRepositoryLocation cvsrl=CVSRepositoryLocation.fromProperties(prop); + + IConnectionMethod method=cvsrl.getMethod(); + psc=method.createConnection(cvsrl, password); + } + catch(Exception e){ + throw new CVSAuthenticationException(e.toString()); + } + psc.open(monitor); + } + + class MyUserInfo implements UserInfo{ + private String username; + private String password; + private String passphrase; + MyUserInfo(String username){ + this.username=username; + } + public String getPassword(){ return password; } + public String getPassphrase(){ return passphrase; } + public boolean promptYesNo(String str){ + YesNoPrompt prompt=new YesNoPrompt(str); + Display.getDefault().syncExec(prompt); + return prompt.getResult()==SWT.YES; + } + public boolean promptPassphrase(String message){ + PassphrasePrompt prompt=new PassphrasePrompt(message); + Display.getDefault().syncExec(prompt); + String _passphrase=prompt.getPassphrase(); + if(_passphrase!=null)passphrase=_passphrase; + return _passphrase!=null; + } + public boolean promptPassword(String message){ + PasswordPrompt prompt=new PasswordPrompt(message); + Display.getDefault().syncExec(prompt); + String _password=prompt.getPassword(); + if(_password!=null)password=_password; + return _password!=null; + } + public void showMessage(final String foo){ + final Display display=Display.getCurrent(); + display.syncExec(new Runnable(){ + public void run(){ + Shell shell=new Shell(display); + MessageBox box=new MessageBox(shell,SWT.OK); + box.setMessage(foo); + box.open(); + shell.dispose(); + } + }); + } + + private class YesNoPrompt implements Runnable{ + private String prompt; + private int result; + YesNoPrompt(String prompt){ + this.prompt=prompt; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + MessageBox box=new MessageBox(shell,SWT.YES|SWT.NO); + box.setMessage(prompt); + result=box.open(); + shell.dispose(); + } + public int getResult(){ return result; } + } + private class PasswordPrompt implements Runnable{ + private String message; + private String password; + PasswordPrompt(String message){ + this.message=message; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + PasswordDialog dialog=new PasswordDialog(shell, message); + dialog.open(); + shell.dispose(); + password=dialog.getPassword(); + } + public String getPassword(){ + return password; + } + } + private class PassphrasePrompt implements Runnable{ + private String message; + private String passphrase; + PassphrasePrompt(String message){ + this.message=message; + } + public void run(){ + Display display=Display.getCurrent(); + Shell shell=new Shell(display); + PassphraseDialog dialog=new PassphraseDialog(shell, message); + dialog.open(); + shell.dispose(); + passphrase=dialog.getPassphrase(); + } + public String getPassphrase(){ + return passphrase; + } + } + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PassphraseDialog.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PassphraseDialog.java new file mode 100644 index 000000000..ab737e5c3 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PassphraseDialog.java @@ -0,0 +1,99 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; + +/** + * A dialog for prompting for a passphrase. + */ +public class PassphraseDialog extends Dialog { + protected Text passphraseField; + protected String passphrase = null; + + protected String message = null; + + public PassphraseDialog(Shell parentShell, String message) { + super(parentShell); + this.message = message; + } + + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(message); + } + + public void create() { + super.create(); + passphraseField.setFocus(); + } + + protected Control createDialogArea(Composite parent) { + Composite main=new Composite(parent, SWT.NONE); + + GridLayout layout=new GridLayout(); + layout.numColumns=3; + main.setLayout(layout); + main.setLayoutData(new GridData(GridData.FILL_BOTH)); + + if (message!=null) { + Label messageLabel=new Label(main, SWT.WRAP); + messageLabel.setText(message); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan=3; + messageLabel.setLayoutData(data); + } + + createPassphraseFields(main); + return main; + } + + protected void createPassphraseFields(Composite parent) { + new Label(parent, SWT.NONE).setText("Passphrase:"); + passphraseField=new Text(parent, SWT.BORDER); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.widthHint=convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); + passphraseField.setLayoutData(data); + passphraseField.setEchoChar('*'); + + new Label(parent, SWT.NONE); + } + + public String getPassphrase() { + return passphrase; + } + + protected void okPressed() { + String _passphrase = passphraseField.getText(); + if(_passphrase==null || _passphrase.length()==0){ + //messageLabel.setText("passphrase is not given."); + //messageLabel.setForeground(messageLabel.getDisplay().getSystemColor(SWT.COLOR_RED)); + return; + } + passphrase=_passphrase; + super.okPressed(); + } + protected void cancelPressed() { + passphrase=null; + super.cancelPressed(); + } +} diff --git a/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PasswordDialog.java b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PasswordDialog.java new file mode 100644 index 000000000..fea50efdd --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ssh2/src/org/eclipse/team/ccvs/ssh2/PasswordDialog.java @@ -0,0 +1,98 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/********************************************************************** +Copyright (c) 2003, Atsuhiko Yamanaka, JCraft,Inc. and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Common Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/cpl-v10.html + +Contributors: + Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. +**********************************************************************/ +package org.eclipse.team.cvs.ssh2; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; + +public class PasswordDialog extends Dialog { + + protected Text passwordField; + protected String password=null; + + protected String message=null; + + public PasswordDialog(Shell parentShell, String message) { + super(parentShell); + this.message=message; + } + + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(message); + } + + public void create() { + super.create(); + passwordField.setFocus(); + } + + protected Control createDialogArea(Composite parent) { + Composite main=new Composite(parent, SWT.NONE); + GridLayout layout=new GridLayout(); + layout.numColumns=3; + main.setLayout(layout); + main.setLayoutData(new GridData(GridData.FILL_BOTH)); + + if (message!=null) { + Label messageLabel=new Label(main, SWT.WRAP); + messageLabel.setText(message); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan=3; + messageLabel.setLayoutData(data); + } + + createPasswordFields(main); + return main; + } + + protected void createPasswordFields(Composite parent) { + new Label(parent, SWT.NONE).setText("Password:"); + + passwordField=new Text(parent, SWT.BORDER); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.widthHint=convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); + passwordField.setLayoutData(data); + passwordField.setEchoChar('*'); + + new Label(parent, SWT.NONE); + } + + public String getPassword() { + return password; + } + + protected void okPressed() { + String _password=passwordField.getText(); + if(_password==null || _password.length()==0){ + //messageLabel.setText("password is not given."); + //messageLabel.setForeground(messageLabel.getDisplay().getSystemColor(SWT.COLOR_RED)); + return; + } + password=_password; + super.okPressed(); + } + + protected void cancelPressed() { + password=null; + super.cancelPressed(); + } +} |