Browse Source

Add Encoding property to ConnectionInfo to specify what encoding to use for current session.
Fix encoding for command execution, SCP and SFTP to allow usage of file names in different encodings

olegkap_cp 12 years ago
parent
commit
db38a04f8a
26 changed files with 180 additions and 99 deletions
  1. 2 1
      Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs
  2. 24 13
      Renci.SshClient/Renci.SshNet/Common/SshData.cs
  3. 9 0
      Renci.SshClient/Renci.SshNet/ConnectionInfo.cs
  4. 14 2
      Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs
  5. 1 1
      Renci.SshClient/Renci.SshNet/Netconf/NetConfSession.cs
  6. 7 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs
  7. 6 2
      Renci.SshClient/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs
  8. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs
  9. 8 7
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs
  10. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs
  11. 7 4
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs
  12. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs
  13. 5 2
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs
  14. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs
  15. 8 5
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs
  16. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRmDirRequest.cs
  17. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs
  18. 6 3
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpStatRequest.cs
  19. 8 5
      Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs
  20. 5 2
      Renci.SshClient/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs
  21. 5 4
      Renci.SshClient/Renci.SshNet/Sftp/SftpMessage.cs
  22. 17 17
      Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs
  23. 1 1
      Renci.SshClient/Renci.SshNet/SftpClient.cs
  24. 4 2
      Renci.SshClient/Renci.SshNet/SshClient.cs
  25. 3 6
      Renci.SshClient/Renci.SshNet/SshCommand.cs
  26. 4 1
      Renci.SshClient/Renci.SshNet/SubsystemSession.cs

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

@@ -4,6 +4,7 @@ using Renci.SshNet.Common;
 using Renci.SshNet.Messages.Connection;
 using System.Globalization;
 using System.Collections.Generic;
+using System.Text;
 
 namespace Renci.SshNet.Channels
 {
@@ -193,7 +194,7 @@ namespace Renci.SshNet.Channels
         {
             this._channelRequestResponse.Reset();
 
-            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExecRequestInfo(command)));
+            this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExecRequestInfo(command, this.ConnectionInfo.Encoding)));
 
             this.WaitHandle(this._channelRequestResponse);
 

+ 24 - 13
Renci.SshClient/Renci.SshNet/Common/SshData.cs

@@ -235,6 +235,15 @@ namespace Renci.SshNet.Common
         /// </summary>
         /// <returns>string read</returns>
         protected string ReadString()
+        {
+            return this.ReadString(SshData._utf8);
+        }
+
+        /// <summary>
+        /// Reads next string data type from internal buffer.
+        /// </summary>
+        /// <returns>string read</returns>
+        protected string ReadString(Encoding encoding)
         {
             var length = this.ReadUInt32();
 
@@ -242,7 +251,7 @@ namespace Renci.SshNet.Common
             {
                 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue));
             }
-            return _utf8.GetString(this.ReadBytes((int)length), 0, (int)length);
+            return encoding.GetString(this.ReadBytes((int)length), 0, (int)length);
         }
 
 
@@ -372,31 +381,32 @@ namespace Renci.SshNet.Common
             this.Write(data.GetBytes());
         }
 
+
         /// <summary>
-        /// Writes string data into internal buffer using default encoding.
+        /// Writes string data into internal buffer as ASCII.
         /// </summary>
         /// <param name="data">string data to write.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
-        protected void Write(string data)
+        protected void WriteAscii(string data)
         {
-            if (data == null)
-                throw new ArgumentNullException("data");
-
-            var bytes = _utf8.GetBytes(data);
-            this.Write((uint)bytes.Length);
-            this.Write(bytes);
+            this.Write(data, SshData._ascii);
         }
 
         /// <summary>
-        /// Writes string data into internal buffer as ASCII.
+        /// Writes string data into internal buffer using default encoding.
         /// </summary>
         /// <param name="data">string data to write.</param>
-        protected void WriteAscii(string data)
+        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
+        protected void Write(string data)
+        {
+            this.Write(data, SshData._utf8);
+        }
+
+        protected void Write(string data, Encoding encoding)
         {
             if (data == null)
                 throw new ArgumentNullException("data");
 
-            var bytes = _ascii.GetBytes(data);
+            var bytes = encoding.GetBytes(data);
             this.Write((uint)bytes.Length);
             this.Write(bytes);
         }
@@ -435,6 +445,7 @@ namespace Renci.SshNet.Common
             this.WriteAscii(string.Join(",", data));
         }
 
+
         /// <summary>
         /// Writes extension-pair data into internal buffer.
         /// </summary>

+ 9 - 0
Renci.SshClient/Renci.SshNet/ConnectionInfo.cs

@@ -120,6 +120,14 @@ namespace Renci.SshNet
         /// </example>
         public TimeSpan Timeout { get; set; }
 
+        /// <summary>
+        /// Gets or sets the default encoding.
+        /// </summary>
+        /// <value>
+        /// The default encoding.
+        /// </value>
+        public Encoding Encoding { get; set; }
+
         /// <summary>
         /// Gets or sets number of retry attempts when session channel creation failed.
         /// </summary>
@@ -260,6 +268,7 @@ namespace Renci.SshNet
             this.Timeout = TimeSpan.FromSeconds(30);
             this.RetryAttempts = 10;
             this.MaxSessions = 10;
+            this.Encoding = Encoding.UTF8;
 
             this.KeyExchangeAlgorithms = new Dictionary<string, Type>()
             {

+ 14 - 2
Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs

@@ -26,8 +26,19 @@ namespace Renci.SshNet.Messages.Connection
         /// <summary>
         /// Gets command to execute.
         /// </summary>
+        /// <value>
+        /// The command.
+        /// </value>
         public string Command { get; private set; }
 
+        /// <summary>
+        /// Gets the encoding.
+        /// </summary>
+        /// <value>
+        /// The encoding.
+        /// </value>
+        public Encoding Encoding { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ExecRequestInfo"/> class.
         /// </summary>
@@ -41,13 +52,14 @@ namespace Renci.SshNet.Messages.Connection
         /// </summary>
         /// <param name="command">The command.</param>
         /// <exception cref="System.ArgumentNullException"><paramref name="command"/> is null.</exception>
-        public ExecRequestInfo(string command)
+        public ExecRequestInfo(string command, Encoding encoding)
             : this()
         {
             if (command == null)
                 throw new System.ArgumentNullException("command");
 
             this.Command = command;
+            this.Encoding = encoding;
         }
 
         /// <summary>
@@ -67,7 +79,7 @@ namespace Renci.SshNet.Messages.Connection
         {
             base.SaveData();
 
-            this.Write(this.Command);
+            this.Write(this.Command, this.Encoding);
         }
     }
 }

+ 1 - 1
Renci.SshClient/Renci.SshNet/Netconf/NetConfSession.cs

@@ -49,7 +49,7 @@ namespace Renci.SshNet.NetConf
         /// <param name="session">The session.</param>
         /// <param name="operationTimeout">The operation timeout.</param>
         public NetConfSession(Session session, TimeSpan operationTimeout)
-            : base(session, "netconf", operationTimeout)
+            : base(session, "netconf", operationTimeout, Encoding.UTF8)
         {
             ClientCapabilities = new XmlDocument();
             ClientCapabilities.LoadXml("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +

+ 7 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs

@@ -1,5 +1,6 @@
 using System;
 using Renci.SshNet.Sftp.Responses;
+using System.Text;
 
 namespace Renci.SshNet.Sftp.Requests
 {
@@ -19,18 +20,21 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string NewPath { get; private set; }
 
-        public PosixRenameRequest(uint protocolVersion, uint requestId, string oldPath, string newPath, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public PosixRenameRequest(uint protocolVersion, uint requestId, string oldPath, string newPath, Encoding encoding, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.OldPath = oldPath;
             this.NewPath = newPath;
+            this.Encoding = encoding;
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.OldPath);
-            this.Write(this.NewPath);
+            this.Write(this.OldPath, this.Encoding);
+            this.Write(this.NewPath, this.Encoding);
         }
     }
 }

+ 6 - 2
Renci.SshClient/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs

@@ -1,5 +1,6 @@
 using System;
 using Renci.SshNet.Sftp.Responses;
+using System.Text;
 
 namespace Renci.SshNet.Sftp.Requests
 {
@@ -17,17 +18,20 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public StatVfsRequest(uint protocolVersion, uint requestId, string path, Action<SftpExtendedReplyResponse> extendedAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public StatVfsRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpExtendedReplyResponse> extendedAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(extendedAction);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs

@@ -15,23 +15,26 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpLStatRequest(uint protocolVersion, uint requestId, string path, Action<SftpAttrsResponse> attrsAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpLStatRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpAttrsResponse> attrsAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(attrsAction);
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 8 - 7
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs

@@ -15,33 +15,34 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
+        public Encoding Encoding { get; private set; }
+
         public SftpFileAttributes Attributes { get; private set; }
 
-        public SftpMkDirRequest(uint protocolVersion, uint requestId, string path, Action<SftpStatusResponse> statusAction)
-            : base(protocolVersion, requestId, statusAction)
+        public SftpMkDirRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpStatusResponse> statusAction)
+            : this(protocolVersion, requestId, path, encoding, null, statusAction)
         {
-            this.Path = path;
-            this.Attributes = new SftpFileAttributes();
         }
 
-        public SftpMkDirRequest(uint protocolVersion, uint requestId, string path, SftpFileAttributes attributes, Action<SftpStatusResponse> statusAction)
+        public SftpMkDirRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, SftpFileAttributes attributes, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.Attributes = attributes;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
             this.Attributes = this.ReadAttributes();
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
             this.Write(this.Attributes);
         }
     }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs

@@ -15,23 +15,26 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpOpenDirRequest(uint protocolVersion, uint requestId, string path, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpOpenDirRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(handleAction);
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 7 - 4
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs

@@ -19,17 +19,20 @@ namespace Renci.SshNet.Sftp.Requests
 
         public SftpFileAttributes Attributes { get; private set; }
 
-        public SftpOpenRequest(uint protocolVersion, uint requestId, string fileName, Flags flags, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
-            : this(protocolVersion, requestId, fileName, flags, new SftpFileAttributes(), handleAction, statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpOpenRequest(uint protocolVersion, uint requestId, string fileName, Encoding encoding, Flags flags, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
+            : this(protocolVersion, requestId, fileName, encoding, flags, new SftpFileAttributes(), handleAction, statusAction)
         {
         }
 
-        public SftpOpenRequest(uint protocolVersion, uint requestId, string fileName, Flags flags, SftpFileAttributes attributes, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
+        public SftpOpenRequest(uint protocolVersion, uint requestId, string fileName, Encoding encoding, Flags flags, SftpFileAttributes attributes, Action<SftpHandleResponse> handleAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Filename = fileName;
             this.Flags = flags;
             this.Attributes = attributes;
+            this.Encoding = encoding;
 
             this.SetAction(handleAction);
         }
@@ -44,7 +47,7 @@ namespace Renci.SshNet.Sftp.Requests
         {
             base.SaveData();
 
-            this.Write(this.Filename);
+            this.Write(this.Filename, this.Encoding);
             this.Write((uint)this.Flags);
             this.Write(this.Attributes);
         }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs

@@ -15,23 +15,26 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpReadLinkRequest(uint protocolVersion, uint requestId, string path, Action<SftpNameResponse> nameAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpReadLinkRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpNameResponse> nameAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(nameAction);
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 5 - 2
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs

@@ -15,7 +15,9 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpRealPathRequest(uint protocolVersion, uint requestId, string path, Action<SftpNameResponse> nameAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpRealPathRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpNameResponse> nameAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             if (nameAction == null)
@@ -25,6 +27,7 @@ namespace Renci.SshNet.Sftp.Requests
                 throw new ArgumentNullException("status");
 
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(nameAction);
             
         }
@@ -32,7 +35,7 @@ namespace Renci.SshNet.Sftp.Requests
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs

@@ -15,22 +15,25 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Filename { get; private set; }
 
-        public SftpRemoveRequest(uint protocolVersion, uint requestId, string filename, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpRemoveRequest(uint protocolVersion, uint requestId, string filename, Encoding encoding, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Filename = filename;
+            this.Encoding = encoding;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Filename = this.ReadString();
+            this.Filename = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Filename);
+            this.Write(this.Filename, this.Encoding);
         }
     }
 }

+ 8 - 5
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs

@@ -17,25 +17,28 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string NewPath { get; private set; }
 
-        public SftpRenameRequest(uint protocolVersion, uint requestId, string oldPath, string newPath, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpRenameRequest(uint protocolVersion, uint requestId, string oldPath, string newPath, Encoding encoding, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.OldPath = oldPath;
             this.NewPath = newPath;
+            this.Encoding = encoding;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.OldPath = this.ReadString();
-            this.NewPath = this.ReadString();
+            this.OldPath = this.ReadString(this.Encoding);
+            this.NewPath = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.OldPath);
-            this.Write(this.NewPath);
+            this.Write(this.OldPath, this.Encoding);
+            this.Write(this.NewPath, this.Encoding);
         }
     }
 }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpRmDirRequest.cs

@@ -15,22 +15,25 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpRmDirRequest(uint protocolVersion, uint requestId, string path, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpRmDirRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs

@@ -15,26 +15,29 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
+        public Encoding Encoding { get; private set; }
+
         public SftpFileAttributes Attributes { get; private set; }
 
-        public SftpSetStatRequest(uint protocolVersion, uint requestId, string path, SftpFileAttributes attributes, Action<SftpStatusResponse> statusAction)
+        public SftpSetStatRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, SftpFileAttributes attributes, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.Attributes = attributes;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
             this.Attributes = this.ReadAttributes();
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
             this.Write(this.Attributes);
         }
     }

+ 6 - 3
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpStatRequest.cs

@@ -15,23 +15,26 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string Path { get; private set; }
 
-        public SftpStatRequest(uint protocolVersion, uint requestId, string path, Action<SftpAttrsResponse> attrsAction, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; private set; }
+
+        public SftpStatRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action<SftpAttrsResponse> attrsAction, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.Path = path;
+            this.Encoding = encoding;
             this.SetAction(attrsAction);
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.Path = this.ReadString();
+            this.Path = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.Path);
+            this.Write(this.Path, this.Encoding);
         }
     }
 }

+ 8 - 5
Renci.SshClient/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs

@@ -17,25 +17,28 @@ namespace Renci.SshNet.Sftp.Requests
 
         public string ExistingPath { get; set; }
 
-        public SftpSymLinkRequest(uint protocolVersion, uint requestId, string newLinkPath, string existingPath, Action<SftpStatusResponse> statusAction)
+        public Encoding Encoding { get; set; }
+
+        public SftpSymLinkRequest(uint protocolVersion, uint requestId, string newLinkPath, string existingPath, Encoding encoding, Action<SftpStatusResponse> statusAction)
             : base(protocolVersion, requestId, statusAction)
         {
             this.NewLinkPath = newLinkPath;
             this.ExistingPath = existingPath;
+            this.Encoding = encoding;
         }
 
         protected override void LoadData()
         {
             base.LoadData();
-            this.NewLinkPath = this.ReadString();
-            this.ExistingPath = this.ReadString();
+            this.NewLinkPath = this.ReadString(this.Encoding);
+            this.ExistingPath = this.ReadString(this.Encoding);
         }
 
         protected override void SaveData()
         {
             base.SaveData();
-            this.Write(this.NewLinkPath);
-            this.Write(this.ExistingPath);
+            this.Write(this.NewLinkPath, this.Encoding);
+            this.Write(this.ExistingPath, this.Encoding);
         }
     }
 }

+ 5 - 2
Renci.SshClient/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs

@@ -14,12 +14,15 @@ namespace Renci.SshNet.Sftp.Responses
 
         public uint Count { get; private set; }
 
+        public Encoding Encoding { get; private set; }
+
         public KeyValuePair<string, SftpFileAttributes>[] Files { get; private set; }
 
-        public SftpNameResponse(uint protocolVersion)
+        public SftpNameResponse(uint protocolVersion, Encoding encoding)
             : base(protocolVersion)
         {
             this.Files = new KeyValuePair<string, SftpFileAttributes>[0];
+            this.Encoding = encoding;
         }
 
         protected override void LoadData()
@@ -31,7 +34,7 @@ namespace Renci.SshNet.Sftp.Responses
             
             for (int i = 0; i < this.Count; i++)
             {
-                var fileName = this.ReadString();
+                var fileName = this.ReadString(this.Encoding);
                 this.ReadString();   //  This field value has meaningless information
                 var attributes = this.ReadAttributes();
                 this.Files[i] = new KeyValuePair<string, SftpFileAttributes>(fileName, attributes);

+ 5 - 4
Renci.SshClient/Renci.SshNet/Sftp/SftpMessage.cs

@@ -4,16 +4,17 @@ using System.Linq;
 using Renci.SshNet.Common;
 using System.Globalization;
 using Renci.SshNet.Sftp.Responses;
+using System.Text;
 
 namespace Renci.SshNet.Sftp
 {
     internal abstract class SftpMessage : SshData
     {
-        public static SftpMessage Load(uint protocolVersion, byte[] data)
+        public static SftpMessage Load(uint protocolVersion, byte[] data, Encoding encoding)
         {
             var messageType = (SftpMessageTypes)data.FirstOrDefault();
 
-            return Load(protocolVersion, data, messageType);
+            return Load(protocolVersion, data, messageType, encoding);
         }
 
         protected override int ZeroReaderIndex
@@ -152,7 +153,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        private static SftpMessage Load(uint protocolVersion, byte[] data, SftpMessageTypes messageType)
+        private static SftpMessage Load(uint protocolVersion, byte[] data, SftpMessageTypes messageType, Encoding encoding)
         {
             SftpMessage message = null;
 
@@ -171,7 +172,7 @@ namespace Renci.SshNet.Sftp
                     message = new SftpHandleResponse(protocolVersion);
                     break;
                 case SftpMessageTypes.Name:
-                    message = new SftpNameResponse(protocolVersion);
+                    message = new SftpNameResponse(protocolVersion, encoding);
                     break;
                 case SftpMessageTypes.Attrs:
                     message = new SftpAttrsResponse(protocolVersion);

+ 17 - 17
Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs

@@ -58,8 +58,8 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        public SftpSession(Session session, TimeSpan operationTimeout)
-            : base(session, "sftp", operationTimeout)
+        public SftpSession(Session session, TimeSpan operationTimeout, Encoding encoding)
+            : base(session, "sftp", operationTimeout, encoding)
         {
         }
 
@@ -211,7 +211,7 @@ namespace Renci.SshNet.Sftp
                 this._data.RemoveRange(0, packetLength);
 
                 //  Load SFTP Message and handle it
-                var response = SftpMessage.Load(this.ProtocolVersion, packetData);
+                var response = SftpMessage.Load(this.ProtocolVersion, packetData, this.Encoding);
 
                 try
                 {
@@ -275,7 +275,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpOpenRequest(this.ProtocolVersion, this.NextRequestId, path, flags,
+                var request = new SftpOpenRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding, flags,
                     (response) =>
                     {
                         handle = response.Handle;
@@ -414,7 +414,7 @@ namespace Renci.SshNet.Sftp
             SftpFileAttributes attributes = null;
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpLStatRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpLStatRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         attributes = response.Attributes;
@@ -474,7 +474,7 @@ namespace Renci.SshNet.Sftp
         {
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpSetStatRequest(this.ProtocolVersion, this.NextRequestId, path, attributes,
+                var request = new SftpSetStatRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding, attributes,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -533,7 +533,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpOpenDirRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpOpenDirRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         handle = response.Handle;
@@ -604,7 +604,7 @@ namespace Renci.SshNet.Sftp
         {
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpRemoveRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpRemoveRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -631,7 +631,7 @@ namespace Renci.SshNet.Sftp
         {
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpMkDirRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpMkDirRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -658,7 +658,7 @@ namespace Renci.SshNet.Sftp
         {
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpRmDirRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpRmDirRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -689,7 +689,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpRealPathRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpRealPathRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         result = response.Files;
@@ -729,7 +729,7 @@ namespace Renci.SshNet.Sftp
             SftpFileAttributes attributes = null;
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpStatRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpStatRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         attributes = response.Attributes;
@@ -768,7 +768,7 @@ namespace Renci.SshNet.Sftp
             }
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpRenameRequest(this.ProtocolVersion, this.NextRequestId, oldPath, newPath,
+                var request = new SftpRenameRequest(this.ProtocolVersion, this.NextRequestId, oldPath, newPath, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -804,7 +804,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpReadLinkRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new SftpReadLinkRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         result = response.Files;
@@ -845,7 +845,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new SftpSymLinkRequest(this.ProtocolVersion, this.NextRequestId, linkpath, targetpath,
+                var request = new SftpSymLinkRequest(this.ProtocolVersion, this.NextRequestId, linkpath, targetpath, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -882,7 +882,7 @@ namespace Renci.SshNet.Sftp
 
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new PosixRenameRequest(this.ProtocolVersion, this.NextRequestId, oldPath, newPath,
+                var request = new PosixRenameRequest(this.ProtocolVersion, this.NextRequestId, oldPath, newPath, this.Encoding,
                     (response) =>
                     {
                         if (response.StatusCode == StatusCodes.Ok)
@@ -920,7 +920,7 @@ namespace Renci.SshNet.Sftp
             SftpFileSytemInformation information = null;
             using (var wait = new AutoResetEvent(false))
             {
-                var request = new StatVfsRequest(this.ProtocolVersion, this.NextRequestId, path,
+                var request = new StatVfsRequest(this.ProtocolVersion, this.NextRequestId, path, this.Encoding,
                     (response) =>
                     {
                         information = response.GetReply<StatVfsReplyInfo>().Information;

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

@@ -1432,7 +1432,7 @@ namespace Renci.SshNet
         {
             base.OnConnected();
 
-            this._sftpSession = new SftpSession(this.Session, this.OperationTimeout);
+            this._sftpSession = new SftpSession(this.Session, this.OperationTimeout, this.ConnectionInfo.Encoding);
 
             this._sftpSession.Connect();
 

+ 4 - 2
Renci.SshClient/Renci.SshNet/SshClient.cs

@@ -190,7 +190,7 @@ namespace Renci.SshNet
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         public SshCommand CreateCommand(string commandText)
         {
-            return this.CreateCommand(commandText, Encoding.UTF8);
+            return this.CreateCommand(commandText, this.ConnectionInfo.Encoding);
         }
 
         /// <summary>
@@ -199,11 +199,13 @@ namespace Renci.SshNet
         /// <param name="commandText">The command text.</param>
         /// <param name="encoding">The encoding to use for results.</param>
         /// <returns><see cref="SshCommand"/> object which uses specified encoding.</returns>
+        /// <remarks>TThis method will change current default encoding.</remarks>
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="commandText"/> or <paramref name="encoding"/> is null.</exception>
         public SshCommand CreateCommand(string commandText, Encoding encoding)
         {
-            return new SshCommand(this.Session, commandText, encoding);
+            this.ConnectionInfo.Encoding = encoding;
+            return new SshCommand(this.Session, commandText);
         }
 
         /// <summary>

+ 3 - 6
Renci.SshClient/Renci.SshNet/SshCommand.cs

@@ -17,8 +17,6 @@ namespace Renci.SshNet
     /// </summary>
     public partial class SshCommand : IDisposable
     {
-        private Encoding _encoding;
-
         private Session _session;
 
         private ChannelSession _channel;
@@ -93,7 +91,7 @@ namespace Renci.SshNet
 
                 if (this.OutputStream != null && this.OutputStream.Length > 0)
                 {
-                    using (var sr = new StreamReader(this.OutputStream, this._encoding))
+                    using (var sr = new StreamReader(this.OutputStream, this._session.ConnectionInfo.Encoding))
                     {
                         this._result.Append(sr.ReadToEnd());
                     }
@@ -123,7 +121,7 @@ namespace Renci.SshNet
 
                     if (this.ExtendedOutputStream != null && this.ExtendedOutputStream.Length > 0)
                     {
-                        using (var sr = new StreamReader(this.ExtendedOutputStream, this._encoding))
+                        using (var sr = new StreamReader(this.ExtendedOutputStream, this._session.ConnectionInfo.Encoding))
                         {
                             this._error.Append(sr.ReadToEnd());
                         }
@@ -143,7 +141,7 @@ namespace Renci.SshNet
         /// <param name="commandText">The command text.</param>
         /// <param name="encoding">The encoding.</param>
         /// <exception cref="ArgumentNullException">Either <paramref name="session"/>, <paramref name="commandText"/> or <paramref name="encoding"/> is null.</exception>
-        internal SshCommand(Session session, string commandText, Encoding encoding)
+        internal SshCommand(Session session, string commandText)
         {
             if (session == null)
                 throw new ArgumentNullException("session");
@@ -151,7 +149,6 @@ namespace Renci.SshNet
             if (commandText == null)
                 throw new ArgumentNullException("commandText");
 
-            this._encoding = encoding;
             this._session = session;
             this.CommandText = commandText;
             this.CommandTimeout = new TimeSpan(0, 0, 0, 0, -1);

+ 4 - 1
Renci.SshClient/Renci.SshNet/SubsystemSession.cs

@@ -51,6 +51,8 @@ namespace Renci.SshNet.Sftp
         /// </summary>
         protected uint ChannelNumber { get; private set; }
 
+        protected Encoding Encoding { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the SubsystemSession class.
         /// </summary>
@@ -59,7 +61,7 @@ namespace Renci.SshNet.Sftp
         /// <param name="operationTimeout">The operation timeout.</param>
         /// <exception cref="System.ArgumentNullException">session</exception>
         /// <exception cref="ArgumentNullException"><paramref name="session" /> or <paramref name="subsystemName" /> is null.</exception>
-        public SubsystemSession(Session session, string subsystemName, TimeSpan operationTimeout)
+        public SubsystemSession(Session session, string subsystemName, TimeSpan operationTimeout, Encoding encoding)
         {
             if (session == null)
                 throw new ArgumentNullException("session");
@@ -70,6 +72,7 @@ namespace Renci.SshNet.Sftp
             this._session = session;
             this._subsystemName = subsystemName;
             this._operationTimeout = operationTimeout;
+            this.Encoding = encoding;
         }
 
         /// <summary>