/*****************************************************************************
* Copyright (c) 2006, 2007 g-Eclipse Consortium
* 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 development of the original code was made for the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Thomas Koeckerbauer GUP, JKU - initial API and implementation
*****************************************************************************/
package eu.geclipse.terminal.ssh.internal;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jsch.core.IJSchService;
import org.eclipse.swt.widgets.Display;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import eu.geclipse.core.IBidirectionalConnection;
import eu.geclipse.core.portforward.ForwardType;
import eu.geclipse.core.portforward.IForward;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.terminal.ITerminalListener;
import eu.geclipse.terminal.ITerminalPage;
import eu.geclipse.terminal.ITerminalView;
import eu.geclipse.ui.dialogs.ProblemDialog;
import eu.geclipse.ui.widgets.IDropDownEntry;
/**
* A terminal factory which allows to open SSH connected terminals.
*/
public class SshShell implements IDropDownEntry<ITerminalView>, ITerminalListener {
ChannelShell channel;
ITerminalPage terminal;
SSHConnectionInfo userInfo;
private int preConnectCols = -1;
private int preConnectLines;
private int preConnectXPix;
private int preConnectYPix;
public void windowSizeChanged( final int cols, final int lines, final int xPixels, final int yPixels ) {
if ( this.channel.isConnected() ) {
this.channel.setPtySize( cols, lines, xPixels, yPixels );
} else {
this.preConnectCols = cols;
this.preConnectLines = lines;
this.preConnectXPix = xPixels;
this.preConnectYPix = yPixels;
}
}
public void action( final ITerminalView terminalView ) {
SSHWizard sshWizard = new SSHWizard();
sshWizard.init( terminalView );
WizardDialog wizardDialog = new WizardDialog( Display.getCurrent().getActiveShell(),
sshWizard );
wizardDialog.open();
}
/**
* Creates a new SSH terminal session using the specified ssh connection
* information in the specified terminal view.
* @param terminalView the terminal view to add the ssh terminal session to.
* @param sshConnectionInfo the connection information describing the ssh
* session.
* @param forwards list of port forwards to create.
*/
public void createTerminal( final ITerminalView terminalView,
final SSHConnectionInfo sshConnectionInfo,
final List<IForward> forwards ) {
try {
IJSchService service = Activator.getDefault().getJSchService();
if (service == null) {
Display.getDefault().asyncExec( new Runnable() {
public void run() {
ProblemException problemException = new ProblemException( "eu.geclipse.terminal.ssh.problem.no_ssh_service", Activator.PLUGIN_ID ); //$NON-NLS-1$
ProblemDialog.openProblem( null,
Messages.getString( "SshShell.sshTerminal" ), //$NON-NLS-1$
Messages.getString( "SshShell.couldNotGetService" ), //$NON-NLS-1$
problemException );
}
} );
} else {
this.userInfo = sshConnectionInfo;
final Session session = service.createSession( this.userInfo.getHostname(),
this.userInfo.getPort(),
this.userInfo.getUsername() );
session.setUserInfo( this.userInfo );
if ( forwards != null ) {
for ( IForward forward : forwards ) {
if (forward.getType() == ForwardType.LOCAL ) {
session.setPortForwardingL( forward.getBindPort(),
forward.getHostname(),
forward.getPort() );
} else {
session.setPortForwardingR( forward.getBindPort(),
forward.getHostname(),
forward.getPort() );
}
}
}
session.connect();
final IBidirectionalConnection connection = new IBidirectionalConnection() {
public void close() {
SshShell.this.channel.disconnect();
session.disconnect();
}
public InputStream getInputStream() throws IOException {
return SshShell.this.channel.getInputStream();
}
public OutputStream getOutputStream() throws IOException {
return SshShell.this.channel.getOutputStream();
}
};
this.channel = (ChannelShell) session.openChannel( "shell" ); //$NON-NLS-1$
Display.getDefault().syncExec( new Runnable() {
public void run() {
try {
SshShell.this.terminal = terminalView.addTerminal( connection, SshShell.this );
SshShell.this.terminal.setTabName( SshShell.this.userInfo.getHostname() );
SshShell.this.terminal.setDescription( Messages.formatMessage( "SshShell.descriptionWithoutWinTitle", //$NON-NLS-1$
SshShell.this.userInfo.getUsername(),
SshShell.this.userInfo.getHostname() ) );
} catch( final IOException exception ) {
Activator.logException( exception );
}
}
} );
this.channel.connect();
if ( this.preConnectCols != -1 ) {
windowSizeChanged( this.preConnectCols, this.preConnectLines,
this.preConnectXPix, this.preConnectYPix );
}
}
} catch ( final JSchException exception ) {
if ( !this.userInfo.getCanceledPWValue() ) {
Display.getDefault().asyncExec( new Runnable() {
public void run() {
ProblemException problemException = new ProblemException( "eu.geclipse.terminal.ssh.problem.auth_failed", exception, Activator.PLUGIN_ID );
ProblemDialog.openProblem( null,
Messages.getString( "SshShell.sshTerminal" ), //$NON-NLS-1$
Messages.getString( "SshShell.authFailed" ), //$NON-NLS-1$
problemException );
}
} );
}
} catch( Exception exception ){
Activator.logException( exception );
}
}
public void windowTitleChanged( final String windowTitle ) {
this.terminal.setDescription( Messages.formatMessage( "SshShell.descriptionWithWinTitle", //$NON-NLS-1$
this.userInfo.getUsername(),
this.userInfo.getHostname(),
windowTitle ) );
}
/* (non-Javadoc)
* @see eu.geclipse.terminal.ITerminalListener#terminated()
*/
public void terminated() {
// not needed
}
}