context: using System;
  using Tamir.SharpSsh.jsch;
  using System.IO;
  using System.Text;
  using System.Collections;
  
  /* 
   * Scp.cs
   * 
   * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved.
   * 
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   *  	1. Redistributions of source code must retain the above copyright notice,
   *		this list of conditions and the following disclaimer.
   *
   *	    2. Redistributions in binary form must reproduce the above copyright 
   *		notice, this list of conditions and the following disclaimer in 
   *		the documentation and/or other materials provided with the distribution.
   *
   *	    3. The names of the authors may not be used to endorse or promote products
   *		derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
   *  *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   * 
   **/
  
  namespace Tamir.SharpSsh
  {
  	/// <summary>
  	/// Class for handling SCP file transfers over SSH connection.
  	/// </summary>
  	public class Scp : SshTransferProtocolBase
  	{
  		private bool m_recursive = false;
  		private bool m_verbos = false;
  		private bool m_cancelled = false;
  
  		public Scp(string host, string user, string password)
  			: base(host, user, password)
  		{
  		}
  
  		public Scp(string host, string user)
  			: base(host, user)
  		{
  		}
  
  		protected override string ChannelType
  		{
  			get { return "exec"; }
  		}
  
  		/// <summary>
  		///This function is empty, so no channel is connected
  		///on session connect 
  		/// </summary>
  		protected override void ConnectChannel()
  		{
  		}
  
  		/// <summary>
  		/// Gets or sets a value indicating the default recursive transfer behaviour
  		/// </summary>
  		public bool Recursive
  		{
  			get{return m_recursive;}
  			set{m_recursive=value;}
  		}
  
  		/// <summary>
  		/// Gets or sets a value indicating whether trace information should be printed
  		/// </summary>
  		public bool Verbos
  		{
  			get{return m_verbos;}
  			set{m_verbos=value;}
  		}
  
  		public override void Cancel()
  		{
  			m_cancelled = true;
  		}
  
  		/// <summary>
  		/// Creates a directory on the remot server
  		/// </summary>
  		/// <param name="dir">The new directory</param>
  		public override void Mkdir(string dir)
  		{
  			SCP_CheckConnectivity();
  
  			Channel channel=null;
  			Stream server = null;
  			m_cancelled=false;
  
  			SCP_ConnectTo(out channel, out server, dir, true);
  			SCP_EnterIntoDir(server, dir);
  			channel.disconnect();
  		}
  
  		public override void Put(string fromFilePath, string toFilePath)
  		{
  			this.To(fromFilePath, toFilePath);
  		}
  
  		public override void Get(string fromFilePath, string toFilePath)
  		{
  			this.From(fromFilePath, toFilePath);
  		}
  
  		/// <summary>
  		/// Opens a <see cref="ScpStream"/> to be used for reading a file from a remote target
  		/// </summary>
  		/// <param name="host">The name of the remote target</param>
  		/// <param name="user">The user to use on the remote target</param>
  		/// <param name="password">The user's password</param>
  		/// <param name="filePath">The full path, including the filename, on the remote target to read from</param>
  		/// <returns>A <see cref="ScpStream"/> that can be used to read a file</returns>
  		public static ScpStream OpenReadStream(Scp scp, string filePath)
  		{
  			Channel channel = null;
  			Stream server = null;
  			String filename = null;
  			scp.m_cancelled = false;
  			int filesize = 0;
  			string cmd = null;
  			scp.Connect();
  			scp.SCP_ConnectFrom(out channel, out server, filePath, false);
  			MemoryStream stream = new MemoryStream();
  
  			try
  			{
  				//scp.SCP_ConnectFrom(out channel, out server, filePath, false);
  
  				byte[] buf = new byte[1024];
  
  				// send '\0'
  				scp.SCP_SendAck(server);
  				int c = scp.SCP_CheckAck(server);
  
  				//parse scp commands
  				while ((c == 'D') || (c == 'C') || (c == 'E'))
  				{
  					if (scp.m_cancelled)
  						break;
  
  					cmd = "" + (char)c;
  					if (c == 'E')
  					{
  						c = scp.SCP_CheckAck(server);
  						//dir = Path.GetDirectoryName(dir);
  						if (scp.Verbos) Console.WriteLine("E");
  						//send '\0'
  						scp.SCP_SendAck(server);
  						c = (char)scp.SCP_CheckAck(server);
  						continue;
  					}
  
  					// read '0644 ' or '0755 '
  					server.Read(buf, 0, 5);
  					for (int i = 0; i < 5; i++)
  						cmd += (char)buf[i];
  
  					//reading file size
  					filesize = 0;
  					while (true)
  					{
  						server.Read(buf, 0, 1);
  						if (buf[0] == ' ') break;
  						filesize = filesize * 10 + (buf[0] - '0');
  					}
  
  					//reading file name					
  					for (int i = 0; ; i++)
  					{
  						server.Read(buf, i, 1);
  						if (buf[i] == (byte)0x0a)
  						{
  							filename = Util.getString(buf, 0, i);
  							break;
  						}
  					}
  					cmd += " " + filesize + " " + filename;
  					// send '\0'
  					scp.SCP_SendAck(server);
  
  					//Receive file
  					if (c == 'C')
  					{
  						if (scp.Verbos) Console.WriteLine("Sending file modes: " + cmd);
  
  						scp.SCP_ReceiveFile(server, stream, filename, null, filesize);
  						stream.Seek(0, 0);
  
  						break;
  					}
  
  					c = scp.SCP_CheckAck(server);
  				}
  			}
  			catch (Exception e)
  			{
  				if (scp.Verbos)
  					Console.WriteLine("Error: " + e.Message);
  				try
  				{
  					channel.disconnect();
  				}
  				catch { }
  				throw e;
  			}
  
  
  			return new ScpStream(channel, stream, false);
  		}
  	
  		/// <summary>
  		/// Opens a <see cref="ScpStream"/> to be used for writing a file to a remote target
  		/// </summary>
  		/// <param name="host">The name of the remote target</param>
  		/// <param name="user">The user to use on the remote target</param>
  		/// <param name="password">The user's password</param>
  		/// <param name="filePath">The full path, including the filename, on the remote target to write into</param>
  		/// <param name="filesize">The size, in bytes, of the file being written</param>
  		/// <returns>A <see cref="ScpStream"/> that can be used to write a file</returns>
  		public static ScpStream OpenWriteStream(Scp scp, string filePath, long filesize)
  		{
  			Channel channel = null;
  			Stream server = null;
  			scp.Connect();
  			scp.SCP_ConnectTo(out channel, out server, filePath, false);
  
  			// send "C0644 filesize filename", where filename should not include '/'
  			string command = "C0644 " + filesize + " " + Path.GetFileName(filePath) + "\n";
  			byte[] buff = Util.getBytes(command);
  			server.Write(buff, 0, buff.Length); server.Flush();
  
  			return new ScpStream(channel, server, true);
  		}
  
  		/// <summary>
  		/// Copies a file from local machine to a remote SSH machine.
  		/// </summary>
  		/// <param name="localPath">The local file path.</param>
  		/// <param name="remotePath">The path of the remote file.</param>
  		public void To(string localPath, string remotePath)
  		{
  			this.To(localPath, remotePath, Recursive);
  		}
  
  		/// <summary>
  		/// Copies a file from a stream to a remote SSH machine.
  		/// </summary>
  		/// <param name="fileStream">The stream for the file.</param>
  		/// <param name="remotePath">The path of the remote file.</param>
  		public void To(Stream fileStream, string remotePath)
  		{
  			To(null, fileStream, remotePath, false);
  			
  		}
  
  		/// <summary>
  		/// Copies a file from local machine to a remote SSH machine.
  		/// </summary>
  		/// <param name="localPath">The local file path.</param>
  		/// <param name="remotePath">The path of the remote file.</param>
  		public void To(string localPath, string remotePath, bool _recursive)
  		{
  			To(localPath, null, remotePath, _recursive);
  		}
  
  		/// <summary>
  		/// Copies a file from local machine to a remote SSH machine.
  		/// </summary>
  		/// <param name="localPath">The local file path.</param>
  		/// <param name="fileStream">The stream for the file.</param>
  		/// <param name="remotePath">The path of the remote file.</param>
  		private void To(string localPath, Stream fileStream, string remotePath, bool _recursive)
  		{
  			SCP_CheckConnectivity();
  
  			Channel channel = null;
  			Stream server = null;
  			m_cancelled = false;
  
  			try
  			{
  				if (fileStream != null)
  				{
  					SCP_ConnectTo(out channel, out server, remotePath, false);
  					SCP_SendFile(server, fileStream, remotePath);
  					channel.disconnect();
  				}
  				//if we are sending a single file
  				else if (localPath != null && File.Exists(localPath))
  				{
  					SCP_ConnectTo(out channel, out server, remotePath, _recursive);
  					SCP_SendFile(server, localPath, remotePath);
  					channel.disconnect();
  				}
  				//else, if we are sending a local directory
  				else if (localPath != null && Directory.Exists(localPath))
  				{
  					if (!_recursive)
  					{
  						throw new SshTransferException(Path.GetFileName("'" + localPath) + "' is a directory, you should use recursive transfer.");
  					}
  					SCP_ConnectTo(out channel, out server, remotePath, true);
  					ToRecursive(server, localPath, remotePath);
  					channel.disconnect();
  				}
  				else
  				{
  					throw new SshTransferException("File not found: " + localPath);
  				}
  			}
  			catch (Exception e)
  			{
  				if (Verbos)
  					Console.WriteLine("Error: " + e.Message);
  				//SendEndMessage(remoteFile, localFile, filesize,filesize, "Transfer ended with an error.");
  				try { channel.disconnect(); }
  				catch { }
  				throw e;
  			}
  		}
  
  		/// <summary>
  		/// Copies files and directories from local machine to a remote SSH machine using SCP.
  		/// </summary>
  		/// <param name="server">I/O Stream for the remote server</param>
  		/// <param name="src">Source to copy</param>
  		/// <param name="dst">Destination path</param>
  		private void ToRecursive(Stream server, string src, string dst)
  		{
  			if(Directory.Exists(src))
  			{
  				SCP_EnterIntoDir(server, Path.GetFileName(dst));
  				foreach(string file in Directory.GetFiles(src))
  				{
  					SCP_SendFile(server, file, Path.GetFileName( file));
  				}
  				if(m_cancelled)
  				{
  					return;
  				}
  				foreach(string dir in Directory.GetDirectories(src))
  				{
  					ToRecursive(server, dir, Path.GetFileName(dir));
  				}
  				SCP_EnterIntoParent(server);
  			}
  			else if(File.Exists(src))
  			{
  				SCP_SendFile(server, src, Path.GetFileName(src));
  			}
  			else
  			{
  				throw new SshTransferException("File not found: "+src);
  			}
  		}
  
  		/// <summary>
  		/// Copies a file from a remote SSH machine to the local machine using SCP.
  		/// </summary>
  		/// <param name="remoteFile">The remmote file name</param>
  		/// <param name="localPath">The local destination path</param>
  		public void From(string remoteFile, string localPath)
  		{
  			this.From(remoteFile, localPath, Recursive);
  		}
  
  		/// <summary>
  		/// Copies a file from a remote SSH machine to the local machine using SCP.
  		/// </summary>
  		/// <param name="remoteFile">The remmote file name</param>
  		/// <param name="localPath">The local destination path</param>
  		/// <param name="recursive">Value indicating whether a recursive transfer should take place</param>
  		public void From(string remoteFile, string localPath, bool _recursive)
  		{
  			SCP_CheckConnectivity();
  
  			Channel channel=null;
  			Stream server = null;
  			m_cancelled=false;
  			int filesize=0;
  			String filename=null;
  			string cmd = null;
  
  			try
  			{
  				String dir=null;
  				if(Directory.Exists(localPath))
  				{
  					dir= Path.GetFullPath( localPath );
  				}
  
  				SCP_ConnectFrom(out channel, out server, remoteFile, _recursive);				
  
  				byte[] buf=new byte[1024];
  
  				// send '\0'
  				SCP_SendAck(server);
  				int c=SCP_CheckAck(server);
  				
  				//parse scp commands
  				while((c=='D')||(c=='C')||(c=='E'))
  				{
  					if(m_cancelled)
  						break;
  
  					cmd = ""+(char)c;
  					if(c=='E')
  					{
  						c=SCP_CheckAck(server);
  						dir = Path.GetDirectoryName(dir);
  						if(Verbos) Console.WriteLine("E");
  						//send '\0'
  						SCP_SendAck(server);
  						c=(char)SCP_CheckAck(server);
  						continue;
  					}
  					
  					// read '0644 ' or '0755 '
  					server.Read(buf, 0, 5);
  					for(int i=0;i<5;i++)
  						cmd+=(char)buf[i];
  					
  					//reading file size
  					filesize=0;
  					while(true)
  					{
  						server.Read(buf, 0, 1);
  						if(buf[0]==' ')break;
  						filesize=filesize*10+(buf[0]-'0');
  					}					
  
  					//reading file name					
  					for(int i=0;;i++)
  					{
  						server.Read(buf, i, 1);
  						if(buf[i]==(byte)0x0a)
  						{
  							filename=Util.getString(buf, 0, i);							
  							break;
  						}
  					}
  					cmd += " "+filesize+" "+filename;
  					// send '\0'
  					SCP_SendAck(server);
  
  					//Receive file
  					if(c=='C')
  					{
  						if(Verbos) Console.WriteLine("Sending file modes: "+cmd);
  						SCP_ReceiveFile(server, remoteFile, 
  							dir==null?localPath:dir+"/"+filename,
  							filesize);
  
  						if(m_cancelled)
  							break;
  						
  						// send '\0'
  						SCP_SendAck(server);
  					}
  					//Enter directory
  					else if(c=='D')
  					{
  						if(dir==null)
  						{
  							if(File.Exists(localPath)) throw new SshTransferException("'"+localPath+"' is not a directory");
  							dir = localPath;
  							Directory.CreateDirectory(dir);
  						}
  						if(Verbos) Console.WriteLine("Entering directory: "+cmd);
  						dir += "/"+filename;
  						Directory.CreateDirectory(dir);
  					}
  
  					c=SCP_CheckAck(server);
  				}				
  				channel.disconnect();
  			}
  			catch(Exception e)
  			{
  				if(Verbos)
  					Console.WriteLine("Error: "+e.Message);				
  				try
  				{
  					channel.disconnect();
  				}
  				catch{}
  				throw e;
  			}
  		}
  
  		#region SCP private functions
  
  		/// <summary>
  		/// Checks is a channel is already connected by this instance
  		/// </summary>
  		protected void SCP_CheckConnectivity()
  		{
  			if(!Connected)
  				throw new Exception("Channel is down.");
  		}
  
  		/// <summary>
  		/// Connect a channel to the remote server using the 'SCP TO' command ('scp -t')
  		/// </summary>
  		/// <param name="channel">Will contain the new connected channel</param>
  		/// <param name="server">Will contaun the new connected server I/O stream</param>
  		/// <param name="rfile">The remote path on the server</param>
  		/// <param name="recursive">Idicate a recursive scp transfer</param>
  		protected void SCP_ConnectTo(out Channel channel, out Stream server, string rfile, bool recursive)
  		{
  			string scpCommand = "scp -p -t ";
  			if(recursive) scpCommand += "-r ";
  			scpCommand += "\""+rfile+"\"";
  
  			channel = (ChannelExec)m_session.openChannel(ChannelType); 
  			((ChannelExec)channel).setCommand(scpCommand);
  
  			server = 
  				new Tamir.Streams.CombinedStream
  				(channel.getInputStream(), channel.getOutputStream());
  			channel.connect();
  
  			SCP_CheckAck(server);
  
  			((Tamir.Streams.CombinedStream)server).UpdateThreadsFromChannel(channel);
  		}
  
  		/// <summary>
  		/// Connect a channel to the remote server using the 'SCP From' command ('scp -f')
  		/// </summary>
  		/// <param name="channel">Will contain the new connected channel</param>
  		/// <param name="server">Will contaun the new connected server I/O stream</param>
  		/// <param name="rfile">The remote path on the server</param>
  		/// <param name="recursive">Idicate a recursive scp transfer</param>
  		protected void SCP_ConnectFrom(out Channel channel, out Stream server, string rfile, bool recursive)
  		{
  			string scpCommand = "scp -f ";
  			if(recursive) scpCommand += "-r ";
  			scpCommand += "\""+rfile+"\"";
  
  			channel = (ChannelExec)m_session.openChannel(ChannelType); 
  			((ChannelExec)channel).setCommand(scpCommand);
  
  			server = 
  				new Tamir.Streams.CombinedStream
  				(channel.getInputStream(), channel.getOutputStream());
  			channel.connect();
  
  			//SCP_CheckAck(server);
  		}
  
  		/// <summary>
  		/// Transfer a file to the remote server
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		/// <param name="src">The source file to copy</param>
  		/// <param name="dst">The remote destination path</param>
  		protected void SCP_SendFile(Stream server, string src, string dst)
  		{
  			//int filesize = 0;
  			//int copied = 0;
  
  			//filesize=(int)(new FileInfo(src)).Length;				
  
  			//byte[] tmp=new byte[1];
  
  			//// send "C0644 filesize filename", where filename should not include '/'
  							
  			//string command="C0644 "+filesize+" "+Path.GetFileName(dst)+"\n";
  			//if(Verbos) Console.WriteLine("Sending file modes: "+command);
  			//SendStartMessage(src, dst, filesize, "Starting transfer.");
  			//byte[] buff = Util.getBytes(command);
  			//server.Write(buff, 0, buff.Length); server.Flush();
  
  			//if(SCP_CheckAck(server)!=0)
  			//{
  			//    throw new SshTransferException("Error openning communication channel.");				
  			//}
  
  			//// send a content of lfile
  			//SendProgressMessage(src, dst, copied, filesize, "Transferring...");
  			FileStream fis=File.OpenRead(src);
  			SCP_SendFile(server, fis, dst);
  			fis.Close();
  			//byte[] buf=new byte[1024*10*2];
  
  			//while(!m_cancelled)
  			//{
  			//    int len=fis.Read(buf, 0, buf.Length);
  			//    if(len<=0) break;
  			//    server.Write(buf, 0, len); server.Flush();
  			//    copied += len;
  			//    SendProgressMessage(src, dst, copied, filesize, "Transferring...");
  			//}
  			//fis.Close();
  
  			//if(m_cancelled)
  			//    return;
  
  			//// send '\0'
  			//buf[0]=0; server.Write(buf, 0, 1); server.Flush();
  		
  			//SendProgressMessage(src, dst, copied, filesize, "Verifying transfer...");
  			//if(SCP_CheckAck(server)!=0)
  			//{
  			//    SendEndMessage(src, dst,copied,filesize, "Transfer ended with an error.");
  			//    throw new SshTransferException("Unknow error during file transfer.");				
  			//}
  			//SendEndMessage(src, dst, copied, filesize, "Transfer completed successfuly ("+copied+" bytes).");
  		}
  
  		/// <summary>
  		/// Transfer a file to the remote server
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		/// <param name="src">The source file to copy</param>
  		/// <param name="dst">The remote destination path</param>
  		protected void SCP_SendFile(Stream server, Stream src, string dst)
  		{
  			int filesize = 0;
  			int copied = 0;
  
  			filesize = (int)src.Length;
  
  			byte[] tmp = new byte[1];
  
  			// send "C0644 filesize filename", where filename should not include '/'
  
  			string command = "C0644 " + filesize + " " + Path.GetFileName(dst) + "\n";
  			if (Verbos) Console.WriteLine("Sending file modes: " + command);
  			SendStartMessage(src.ToString(), dst, filesize, "Starting transfer.");
  			byte[] buff = Util.getBytes(command);
  			server.Write(buff, 0, buff.Length); server.Flush();
  
  			if (SCP_CheckAck(server) != 0)
  			{
  				throw new SshTransferException("Error openning communication channel.");
  			}
  
  			// send a content of lfile
  			SendProgressMessage(src.ToString(), dst, copied, filesize, "Transferring...");
  
  			byte[] buf = new byte[1024 * 10 * 2];
  
  			while (!m_cancelled)
  			{
  				int len = src.Read(buf, 0, buf.Length);
  				if (len <= 0) break;
  				server.Write(buf, 0, len); server.Flush();
  				copied += len;
  				SendProgressMessage("stream", dst, copied, filesize, "Transferring...");
  			}
  			//src.Close();
  
  			if (m_cancelled)
  				return;
  
  			// send '\0'
  			buf[0] = 0; server.Write(buf, 0, 1); server.Flush();
  
  			SendProgressMessage(src.ToString(), dst, copied, filesize, "Verifying transfer...");
  			if (SCP_CheckAck(server) != 0)
  			{
  				SendEndMessage(src.ToString(), dst, copied, filesize, "Transfer ended with an error.");
  				throw new SshTransferException("Unknow error during file transfer.");
  			}
  			SendEndMessage(src.ToString(), dst, copied, filesize, "Transfer completed successfuly (" + copied + " bytes).");
  		}
  
  		/// <summary>
  		/// Transfer a file from the remote server
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		/// <param name="rfile">The remote file to copy</param>
  		/// <param name="lfile">The local destination path</param>
  		protected void SCP_ReceiveFile(Stream server, string rfile, string lfile, int size)
  		{
  			FileStream fos=File.OpenWrite(lfile);
  
  			SCP_ReceiveFile(server, fos, rfile, lfile, size);
  	
  			fos.Close();
  		}
  
  		/// <summary>
  		/// Transfer a file from the remote server
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		/// <param name="fos">The local stream to copy the file into</param>
  		/// <param name="rfile">The remote file to copy</param>
  		/// <param name="lfile">The local destination path</param>
  		protected void SCP_ReceiveFile(Stream server, Stream fos, string rfile, string lfile, int size)
  		{
  			int copied = 0;
  			SendStartMessage(rfile, lfile != null ? lfile : fos.ToString(), size, "Connected, starting transfer.");
  			// read a content of lfile
  			int foo;
  			int filesize = size;
  			byte[] buf = new byte[1024];
  			while (!m_cancelled)
  			{
  				if (buf.Length < filesize) foo = buf.Length;
  				else foo = filesize;
  				int len = server.Read(buf, 0, foo);
  				copied += len;
  				fos.Write(buf, 0, foo);
  				SendProgressMessage(rfile, lfile, copied, size, "Transferring...");
  				filesize -= foo;
  				if (filesize == 0) break;
  			}
  			if (m_cancelled)
  				return;
  			SCP_CheckAck(server);
  			SendEndMessage(rfile, lfile, copied, size, "Transfer completed successfuly (" + filesize + " bytes).");
  		}
  
  		/// <summary>
  		/// Instructs the remote server to enter into a directory
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		/// <param name="dir">The directory name/param>
  		protected void SCP_EnterIntoDir(Stream server, string dir)
  		{
  			try
  			{
  				byte[] tmp=new byte[1];
  
  				// send "C0644 filesize filename", where filename should not include '/'
  								
  				string command="D0755 0 "+Path.GetFileName(dir)+"\n";
  				if(Verbos) Console.WriteLine("Enter directory: "+command);
  				
  				byte[] buff = Util.getBytes(command);
  				server.Write(buff, 0, buff.Length); server.Flush();
  
  				if(SCP_CheckAck(server)!=0)
  				{
  					throw new SshTransferException("Error openning communication channel.");				
  				}
  			}
  			catch{}
  		}
  
  		/// <summary>
  		/// Instructs the remote server to go up one level
  		/// </summary>
  		/// <param name="server">A connected server I/O stream</param>
  		protected void SCP_EnterIntoParent(Stream server)
  		{
  			try
  			{
  				byte[] tmp=new byte[1];
  
  				// send "C0644 filesize filename", where filename should not include '/'
  								
  				string command="E\n";
  				if(Verbos) Console.WriteLine(command);
  				
  				byte[] buff = Util.getBytes(command);
  				server.Write(buff, 0, buff.Length); server.Flush();
  
  				if(SCP_CheckAck(server)!=0)
  				{
  					throw new SshTransferException("Error openning communication channel.");				
  				}
  			}
  			catch{}
  		}
  
  		/// <summary>
  		/// Gets server acknowledgment
  		/// </summary>
  		/// <param name="ins">A connected server I/O stream</param>
  		private int SCP_CheckAck(Stream ins) 
  		{
  			int b=ins.ReadByte();
  			// 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)
  			{
  
gt: 				StringBuilder sb=new StringBuilder();