瀏覽代碼

Add ability to specify terminal modes for Shell terminal
Example:
using (var ssh = new SshClient(connectionInfo))
{
ssh.Connect();
var output = Console.OpenStandardOutput();
var input = Console.OpenStandardInput();
var terminalModes = new Dictionary<TerminalModes, uint>();
terminalModes.Add(TerminalModes.ECHO, 0);
terminalModes.Add(TerminalModes.VERASE, 0x7F);
terminalModes.Add(TerminalModes.TTY_OP_ISPEED, 0x9600);
terminalModes.Add(TerminalModes.TTY_OP_OSPEED, 0x9600);

var shell = ssh.CreateShell(input, output, output, "xterm", 80, 24, 0, 0, terminalModes);
shell.Stopped += delegate
{
Console.WriteLine("\nDisconnected...");
};
shell.Start();
Thread.Sleep(1000 * 100);
shell.Stop();
}

olegkap_cp 13 年之前
父節點
當前提交
a9a006e220

+ 1 - 1
Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs

@@ -122,7 +122,7 @@ namespace Renci.SshNet.Channels
         /// <returns>
         /// true if request was successful; otherwise false.
         /// </returns>
-        public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, params KeyValuePair<TerminalModes, uint>[] terminalModeValues)
+        public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues)
         {
             this._channelRequestResponse.Reset();
 

+ 15 - 31
Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs

@@ -70,7 +70,7 @@ namespace Renci.SshNet.Messages.Connection
         /// <value>
         /// The terminal mode.
         /// </value>
-        public KeyValuePair<TerminalModes, uint>[] TerminalModeValues { get; set; }
+        public IDictionary<TerminalModes, uint> TerminalModeValues { get; set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PseudoTerminalRequestInfo"/> class.
@@ -89,7 +89,7 @@ namespace Renci.SshNet.Messages.Connection
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
         /// <param name="terminalModeValues">The terminal mode values.</param>
-        public PseudoTerminalRequestInfo(string environmentVariable, uint columns, uint rows, uint width, uint height, params KeyValuePair<TerminalModes, uint>[] terminalModeValues)
+        public PseudoTerminalRequestInfo(string environmentVariable, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues)
             : this()
         {
             this.EnvironmentVariable = environmentVariable;
@@ -100,29 +100,6 @@ namespace Renci.SshNet.Messages.Connection
             this.TerminalModeValues = terminalModeValues;
         }
 
-        /// <summary>
-        /// Called when type specific data need to be loaded.
-        /// </summary>
-        protected override void LoadData()
-        {
-            base.LoadData();
-
-            this.EnvironmentVariable = this.ReadString();
-            this.Columns = this.ReadUInt32();
-            this.Rows = this.ReadUInt32();
-            this.PixelWidth = this.ReadUInt32();
-            this.PixelHeight = this.ReadUInt32();
-
-            var length = this.ReadUInt32();
-
-            this.TerminalModeValues = new KeyValuePair<TerminalModes, uint>[(length - 1) / 5];
-            for (int i = 0; i < length; i++)
-            {
-                var keyValue = new KeyValuePair<TerminalModes, uint>((TerminalModes)this.ReadByte(), this.ReadUInt32());
-                this.TerminalModeValues[i] = keyValue;
-            }
-        }
-
         /// <summary>
         /// Called when type specific data need to be saved.
         /// </summary>
@@ -136,14 +113,21 @@ namespace Renci.SshNet.Messages.Connection
             this.Write(this.Rows);
             this.Write(this.PixelHeight);
 
-            this.Write((uint)this.TerminalModeValues.Length * 5 + 1);
-
-            foreach (var item in this.TerminalModeValues)
+            if (this.TerminalModeValues != null)
+            {
+                this.Write((uint)this.TerminalModeValues.Count * (1 + 4) + 1);
+
+                foreach (var item in this.TerminalModeValues)
+                {
+                    this.Write((byte)item.Key);
+                    this.Write(item.Value);
+                }
+                this.Write((byte)0);
+            }
+            else
             {
-                this.Write((byte)item.Key);
-                this.Write((uint)item.Value);                
+                this.Write((uint)0);
             }
-            this.Write((byte)0);
         }
     }
 }

+ 6 - 2
Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs

@@ -139,9 +139,13 @@ namespace Renci.SshNet.Security
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="DsaKey"/> class.
+        /// Initializes a new instance of the <see cref="DsaKey" /> class.
         /// </summary>
-        /// <param name="keys">The keys.</param>
+        /// <param name="p">The p.</param>
+        /// <param name="q">The q.</param>
+        /// <param name="g">The g.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="x">The x.</param>
         public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x)
         {
             this._privateKey = new BigInteger[5];

+ 15 - 7
Renci.SshClient/Renci.SshNet/SftpClient.cs

@@ -329,8 +329,9 @@ namespace Renci.SshNet
         /// <param name="path">The path.</param>
         /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</param>
         /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
+        /// <param name="listCallback">The list callback.</param>
         /// <returns>
-        /// An <see cref="IAsyncResult"/> that references the asynchronous operation.
+        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
         /// </returns>
         public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, object state, Action<int> listCallback = null)
         {
@@ -466,13 +467,20 @@ namespace Renci.SshNet
         /// <param name="output">The output.</param>
         /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</param>
         /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
-        /// <returns>An <see cref="IAsyncResult"/> that references the asynchronous operation.</returns>
-        /// <exception cref="ArgumentNullException"><paramref name="output"/> is <b>null</b>.</exception>
-        /// <exception cref="ArgumentException"><paramref name="path"/> is <b>null</b> or contains whitespace characters.</exception>
+        /// <param name="downloadCallback">The download callback.</param>
+        /// <returns>
+        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
+        /// </returns>
+        /// <exception cref="System.ArgumentException">path</exception>
+        /// <exception cref="System.ArgumentNullException">output</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <b>null</b>.</exception>
+        /// <exception cref="ArgumentException"><paramref name="path" /> is <b>null</b> or contains whitespace characters.</exception>
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         /// <exception cref="Renci.SshNet.Common.SftpPermissionDeniedException">Permission to perform the operation was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
-        /// <exception cref="Renci.SshNet.Common.SshException">A SSH error where <see cref="P:SshException.Message"/> is the message from the remote host.</exception>
-        /// <remarks>Method calls made by this method to <paramref name="output"/>, may under certain conditions result in exceptions thrown by the stream.</remarks>
+        /// <exception cref="Renci.SshNet.Common.SshException">A SSH error where <see cref="P:SshException.Message" /> is the message from the remote host.</exception>
+        /// <remarks>
+        /// Method calls made by this method to <paramref name="output" />, may under certain conditions result in exceptions thrown by the stream.
+        /// </remarks>
         public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback, object state, Action<ulong> downloadCallback = null)
         {
             if (path.IsNullOrWhiteSpace())
@@ -1247,7 +1255,7 @@ namespace Renci.SshNet
         /// Internals the list directory.
         /// </summary>
         /// <param name="path">The path.</param>
-        /// <param name="asynchResult">The asynch result.</param>
+        /// <param name="listCallback">The list callback.</param>
         /// <returns></returns>
         /// <exception cref="System.ArgumentNullException">path</exception>
         /// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>

+ 5 - 5
Renci.SshClient/Renci.SshNet/Shell.cs

@@ -7,6 +7,7 @@ using System.Threading;
 using Renci.SshNet.Channels;
 using Renci.SshNet.Common;
 using Renci.SshNet.Messages.Connection;
+using System.Collections.Generic;
 
 namespace Renci.SshNet
 {
@@ -33,7 +34,7 @@ namespace Renci.SshNet
 
         private uint _height;
 
-        private string _terminalMode;
+        private IDictionary<TerminalModes, uint> _terminalModes;
 
         private EventWaitHandle _dataReaderTaskCompleted;
 
@@ -90,7 +91,7 @@ namespace Renci.SshNet
         /// <param name="height">The height.</param>
         /// <param name="terminalMode">The terminal mode.</param>
         /// <param name="bufferSize">Size of the buffer for output stream.</param>
-        internal Shell(Session session, Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode, int bufferSize)
+        internal Shell(Session session, Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes, int bufferSize)
         {
             this._session = session;
             this._input = input;
@@ -101,7 +102,7 @@ namespace Renci.SshNet
             this._rows = rows;
             this._width = width;
             this._height = height;
-            this._terminalMode = terminalMode;
+            this._terminalModes = terminalModes;
             this._bufferSize = bufferSize;
         }
 
@@ -129,8 +130,7 @@ namespace Renci.SshNet
             this._session.ErrorOccured += Session_ErrorOccured;
 
             this._channel.Open();
-            //  TODO:   Terminal mode is ignored as this functionality will be obsolete
-            this._channel.SendPseudoTerminalRequest(this._terminalName, this._columns, this._rows, this._width, this._height);
+            this._channel.SendPseudoTerminalRequest(this._terminalName, this._columns, this._rows, this._width, this._height, this._terminalModes);
             this._channel.SendShellRequest();
 
             this._channelClosedWaitHandle = new AutoResetEvent(false);

+ 1 - 1
Renci.SshClient/Renci.SshNet/ShellStream.cs

@@ -51,7 +51,7 @@ namespace Renci.SshNet
             }
         }
 
-        internal ShellStream(Session session, string terminalName, uint columns, uint rows, uint width, uint height, int maxLines, params KeyValuePair<TerminalModes, uint>[] terminalModeValues)
+        internal ShellStream(Session session, string terminalName, uint columns, uint rows, uint width, uint height, int maxLines, IDictionary<TerminalModes, uint> terminalModeValues)
         {
             this._encoding = new Renci.SshNet.Common.ASCIIEncoding();
             this._session = session;

+ 30 - 18
Renci.SshClient/Renci.SshNet/SshClient.cs

@@ -220,15 +220,15 @@ namespace Renci.SshNet
         /// <param name="rows">The rows.</param>
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
-        /// <param name="terminalMode">The terminal mode.</param>
+        /// <param name="terminalModes">The terminal mode.</param>
         /// <param name="bufferSize">Size of the internal read buffer.</param>
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
-        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode, int bufferSize)
+        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes, int bufferSize)
         {
             //  Ensure that connection is established.
             this.EnsureConnection();
 
-            return new Shell(this.Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, bufferSize);
+            return new Shell(this.Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
         }
 
         /// <summary>
@@ -242,11 +242,11 @@ namespace Renci.SshNet
         /// <param name="rows">The rows.</param>
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
-        /// <param name="terminalMode">The terminal mode.</param>
+        /// <param name="terminalModes">The terminal mode.</param>
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
-        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode)
+        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes)
         {
-            return this.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, 1024);
+            return this.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
         }
 
         /// <summary>
@@ -258,7 +258,7 @@ namespace Renci.SshNet
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
         public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
         {
-            return this.CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, string.Empty, 1024);
+            return this.CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);
         }
 
         /// <summary>
@@ -273,21 +273,18 @@ namespace Renci.SshNet
         /// <param name="rows">The rows.</param>
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
-        /// <param name="terminalMode">The terminal mode.</param>
+        /// <param name="terminalModes">The terminal mode.</param>
         /// <param name="bufferSize">Size of the internal read buffer.</param>
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
-        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode, int bufferSize)
+        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes, int bufferSize)
         {
-            //  Ensure that connection is established.
-            this.EnsureConnection();
-
             this._inputStream = new MemoryStream();
             var writer = new StreamWriter(this._inputStream, encoding);
             writer.Write(input);
             writer.Flush();
             this._inputStream.Seek(0, SeekOrigin.Begin);
 
-            return this.CreateShell(this._inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, bufferSize);
+            return this.CreateShell(this._inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
         }
 
         /// <summary>
@@ -304,9 +301,9 @@ namespace Renci.SshNet
         /// <param name="height">The height.</param>
         /// <param name="terminalMode">The terminal mode.</param>
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
-        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode)
+        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes)
         {
-            return this.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, 1024);
+            return this.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
         }
 
         /// <summary>
@@ -319,7 +316,7 @@ namespace Renci.SshNet
         /// <returns>Returns a representation of a <see cref="Shell"/> object.</returns>
         public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput)
         {
-            return this.CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, string.Empty, 1024);
+            return this.CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);
         }
 
         /// <summary>
@@ -333,7 +330,23 @@ namespace Renci.SshNet
         /// <param name="bufferSize">Size of the buffer.</param>
         /// <param name="terminalModeValues">The terminal mode values.</param>
         /// <returns></returns>
-        public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, params KeyValuePair<TerminalModes, uint>[] terminalModeValues)
+        public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize)
+        {
+            return this.CreateShellStream(terminalName, columns, rows, width, height, bufferSize);
+        }
+
+        /// <summary>
+        /// Creates the shell stream.
+        /// </summary>
+        /// <param name="terminalName">Name of the terminal.</param>
+        /// <param name="columns">The columns.</param>
+        /// <param name="rows">The rows.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="bufferSize">Size of the buffer.</param>
+        /// <param name="terminalModeValues">The terminal mode values.</param>
+        /// <returns></returns>
+        public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary<TerminalModes, uint> terminalModeValues)
         {
             //  Ensure that connection is established.
             this.EnsureConnection();
@@ -341,7 +354,6 @@ namespace Renci.SshNet
             return new ShellStream(this.Session, terminalName, columns, rows, width, height, bufferSize, terminalModeValues);
         }
 
-
         /// <summary>
         /// Releases unmanaged and - optionally - managed resources
         /// </summary>