/**************************************************************************** * Copyright (c) 2007 Composent, 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: * Composent, Inc. - initial API and implementation *****************************************************************************/ package org.eclipse.ecf.internal.provider.filetransfer.scp; import com.jcraft.jsch.*; import java.io.*; import java.net.URL; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.ecf.core.security.IConnectContext; import org.eclipse.ecf.core.util.Proxy; import org.eclipse.ecf.filetransfer.IFileTransferPausable; import org.eclipse.ecf.filetransfer.IncomingFileTransferException; import org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer; import org.eclipse.osgi.util.NLS; /** * */ public class ScpRetrieveFileTransfer extends AbstractRetrieveFileTransfer implements IScpFileTransfer { private static final String SCP_COMMAND = System.getProperty( "org.eclipse.ecf.filetransfer.scp.retrieve.scpcommand", "scp -f "); //$NON-NLS-1$ private static final String SCP_EXEC = System.getProperty( "org.eclipse.ecf.filetransfer.scp.retrieve.scpcommand", "exec"); //$NON-NLS-1$ String username; Channel channel; OutputStream responseStream; private ScpUtil scpUtil; /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer * #doPause() */ protected boolean doPause() { return false; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer * #doResume() */ protected boolean doResume() { return false; } public URL getTargetURL() { return getRemoteFileURL(); } public Map getOptions() { return options; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.outgoing.AbstractOutgoingFileTransfer * #openStreams() */ protected void openStreams() throws IncomingFileTransferException { try { // Set input stream from local file final URL url = getRemoteFileURL(); this.username = url.getUserInfo(); scpUtil = new ScpUtil(this); final Session s = scpUtil.getSession(); s.connect(); final String command = SCP_COMMAND + scpUtil.trimTargetFile(url.getPath()); channel = s.openChannel(SCP_EXEC); ((ChannelExec) channel).setCommand(command); channel.connect(); final InputStream ins = channel.getInputStream(); responseStream = channel.getOutputStream(); scpUtil.sendZeroToStream(responseStream); final int c = checkAck(ins); if (c != 'C') throw new IOException( Messages.ScpRetrieveFileTransfer_EXCEPTION_SCP_PROTOCOL); // read '0644 ' final byte[] buf = new byte[1024]; ins.read(buf, 0, 5); setFileLength(readFileSize(ins, buf)); readFileName(ins, buf); // set input stream for reading rest of file remoteFileContents = ins; scpUtil.sendZeroToStream(responseStream); fireReceiveStartEvent(); } catch (final Exception e) { channel = null; username = null; throw new IncomingFileTransferException(NLS.bind( Messages.ScpRetrieveFileTransfer_EXCEPTION_CONNECTING, getRemoteFileURL().toString()), e); } } static int checkAck(InputStream in) throws IOException { int b = in.read(); // b may be 0 for success, // 1 for error, // 2 for fatal error, // -1 if (b == 0) return b; if (b == -1) return b; if (b == 1 || b == 2) { StringBuffer sb = new StringBuffer(); int c; do { c = in.read(); sb.append((char) c); } while (c != '\n'); if (b == 1 || b == 2) { // error throw new IOException( Messages.ScpRetrieveFileTransfer_EXCEPTION_SCP_PROTOCOL + ": " + sb.toString()); } } return b; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer * #handleReceivedData(byte[], int, double, * org.eclipse.core.runtime.IProgressMonitor) */ protected void handleReceivedData(byte[] buf, int bytes, double factor, IProgressMonitor monitor) throws IOException { if (bytes == -1) { done = true; } else { int fileBytes = bytes; if ((bytesReceived + bytes) > fileLength) { fileBytes = (int) (fileLength - bytesReceived); } bytesReceived += fileBytes; localFileContents.write(buf, 0, fileBytes); fireTransferReceiveDataEvent(); monitor.worked((int) Math.round(factor * fileBytes)); if (fileBytes != bytes) { scpUtil.checkAck(buf[fileBytes], remoteFileContents); done = true; } } } private long readFileSize(InputStream ins, byte[] buf) throws IOException { long filesize = 0L; while (true) { if (ins.read(buf, 0, 1) < 0) { throw new IOException( Messages.ScpRetrieveFileTransfer_EXCEPTION_ERROR_READING_FILE); } if (buf[0] == ' ') break; filesize = filesize * 10L + (buf[0] - '0'); } return filesize; } private String readFileName(InputStream ins, byte[] buf) throws IOException { String file = null; for (int i = 0;; i++) { ins.read(buf, i, 1); if (buf[i] == (byte) 0x0a) { file = new String(buf, 0, i); break; } } return file; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.outgoing.AbstractOutgoingFileTransfer * #hardClose() */ protected void hardClose() { try { if (remoteFileContents != null && scpUtil != null) { scpUtil.sendZeroToStream(responseStream); scpUtil.dispose(); scpUtil = null; remoteFileContents = null; responseStream = null; } } catch (final IOException e) { exception = e; } finally { super.hardClose(); channel = null; username = null; } } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer * #getAdapter(java.lang.Class) */ public Object getAdapter(Class adapter) { if (adapter == null) return null; if (adapter.equals(IFileTransferPausable.class)) return null; return super.getAdapter(adapter); } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer * #setupProxy(org.eclipse.ecf.core.util.Proxy) */ protected void setupProxy(Proxy proxy) { this.proxy = proxy; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.scp.IScpFileTransfer#getConnectContext * () */ public IConnectContext getConnectContext() { return connectContext; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.scp.IScpFileTransfer#getUsername() */ public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } /* * (non-Javadoc) * * @see * org.eclipse.ecf.provider.filetransfer.scp.IScpFileTransfer#promptPassphrase * () */ public boolean promptPassphrase() { // XXX TODO // return (keyFile != null); return false; } public Proxy getProxy() { return this.proxy; } }