├── .editorconfig ├── FluentFTP.Tests ├── xunit.runner.json ├── XUnitShim.cs └── Tests.csproj ├── FluentFTP ├── sn.snk ├── restore.bat ├── Helpers │ ├── IntRef.cs │ ├── FtpEvents.cs │ ├── FtpReply.cs │ ├── FtpExceptions.cs │ ├── FtpHash.cs │ ├── FtpListItem.cs │ ├── FtpTrace.cs │ └── FtpEnums.cs ├── Proxy │ ├── ProxyInfo.cs │ ├── FtpClientProxy.cs │ ├── FtpClientUserAtHostProxy.cs │ └── FtpClientHttp11Proxy.cs ├── FluentFTP.csproj ├── Utils │ ├── FtpReflection.cs │ └── FtpExtensions.cs ├── Stream │ ├── FtpDataStream.cs │ └── FtpSslStream.cs └── Client │ └── IFtpClient.cs ├── FluentFTP.Examples ├── Examples.csproj ├── Connect.cs ├── DeleteFile.cs ├── OpenAppendURI.cs ├── OpenWriteURI.cs ├── CreateDirectory.cs ├── SetWorkingDirectory.cs ├── GetFileSize.cs ├── GetWorkingDirectory.cs ├── GetModifiedTime.cs ├── DeleteDirectory.cs ├── SetHashAlgorithm.cs ├── DirectoryExists.cs ├── GetHashAlgorithm.cs ├── OpenWrite.cs ├── Execute.cs ├── Extensions.cs ├── Rename.cs ├── FileExists.cs ├── OpenReadURI.cs ├── GetNameListing.cs ├── ValidateCertificate.cs ├── OpenRead.cs ├── SetEncryptionProtocols.cs ├── GetChecksum.cs ├── OpenAppend.cs ├── BeginConnect.cs ├── Main.cs ├── BeginDisconnect.cs ├── BeginDeleteFile.cs ├── BeginRename.cs ├── BeginSetWorkingDirectory.cs ├── BeginDeleteDirectory.cs ├── BeginFileExists.cs ├── BeginDirectoryExists.cs ├── BeginGetFileSize.cs ├── BeginGetModifiedTime.cs ├── BeginGetWorkingDirectory.cs ├── BeginCreateDirectory.cs ├── BeginExecute.cs ├── BeginGetListing.cs ├── BeginGetNameListing.cs ├── GetHash.cs ├── BeginOpenWrite.cs ├── BeginOpenAppend.cs ├── GetListing.cs ├── BeginDereferenceLink.cs ├── BeginOpenRead.cs ├── Debug.cs ├── DereferenceLink.cs └── CustomParser.cs ├── .gitignore ├── appveyor.yml ├── LICENSE.TXT └── FluentFTP.sln /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | indent_style = tab 3 | -------------------------------------------------------------------------------- /FluentFTP.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method" 3 | } -------------------------------------------------------------------------------- /FluentFTP/sn.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dibble-james/FluentFTP/master/FluentFTP/sn.snk -------------------------------------------------------------------------------- /FluentFTP/restore.bat: -------------------------------------------------------------------------------- 1 | dotnet restore FluentFTP_Core14.csproj 2 | dotnet restore FluentFTP_Core16.csproj 3 | pause -------------------------------------------------------------------------------- /FluentFTP/Helpers/IntRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace FluentFTP 6 | { 7 | internal class IntRef 8 | { 9 | public int Value; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /FluentFTP.Examples/Examples.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net45 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | nuget 4 | 5 | API Reference.shfbproj_jp 6 | Help 7 | 8 | *.sublime-workspace 9 | *.user 10 | *.suo 11 | *.nupkg 12 | .gitignore 13 | NuGetPackages 14 | Releases 15 | project.lock.json 16 | project.multitarget.json 17 | 18 | API_Reference_HTML.shfbproj_jp 19 | CHM 20 | HTML 21 | API_Reference_CHM.shfbproj_jp 22 | .DS_Store 23 | .vs 24 | -------------------------------------------------------------------------------- /FluentFTP/Proxy/ProxyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace FluentFTP.Proxy { 4 | /// POCO holding proxy information 5 | public class ProxyInfo { 6 | /// Proxy host name 7 | public string Host { get; set; } 8 | 9 | /// Proxy port 10 | public int Port { get; set; } 11 | 12 | /// Proxy login credentials 13 | public NetworkCredential Credentials { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/Connect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public static class ConnectExample { 7 | public static void Connect() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | conn.Connect(); 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.0.{build} 2 | 3 | image: Visual Studio 2017 4 | 5 | configuration: Release 6 | 7 | before_build: 8 | - cmd: msbuild FluentFTP.sln /t:Restore 9 | 10 | build: 11 | verbosity: minimal 12 | 13 | after_build: 14 | - cmd: msbuild FluentFTP.sln /t:FluentFTP:Pack /p:Configuration=Release 15 | 16 | test_script: 17 | - cmd: >- 18 | dotnet test fluentftp.tests -f net452 19 | dotnet test fluentftp.tests -f netcoreapp1.0 20 | 21 | artifacts: 22 | - path: '**\*.nupkg' 23 | -------------------------------------------------------------------------------- /FluentFTP.Examples/DeleteFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class DeleteFileExample { 7 | public static void DeleteFile() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | conn.DeleteFile("/full/or/relative/path/to/file"); 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenAppendURI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | class OpenAppendURI { 7 | public static void OpenURI() { 8 | using (Stream s = FtpClient.OpenAppend(new Uri("ftp://server/path/file"))) { 9 | try { 10 | // write data to the file on the server 11 | } 12 | finally { 13 | s.Close(); 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenWriteURI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class OpenWriteURI { 7 | public static void OpenURI() { 8 | using (Stream s = FtpClient.OpenWrite(new Uri("ftp://server/path/file"))) { 9 | try { 10 | // write data to the file on the server 11 | } 12 | finally { 13 | s.Close(); 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FluentFTP.Examples/CreateDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | 6 | namespace Examples { 7 | public static class CreateDirectoryExample { 8 | public static void CreateDirectory() { 9 | using (FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | conn.CreateDirectory("/test/path/that/should/be/created", true); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FluentFTP.Examples/SetWorkingDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | 6 | namespace Examples { 7 | public static class SetWorkingDirectoryExample { 8 | public static void SetWorkingDirectory() { 9 | using (FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | conn.SetWorkingDirectory("/full/or/relative/path"); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetFileSize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class GetFileSizeExample { 7 | public static void GetFileSize() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | Console.WriteLine("The file size is: "+ 12 | conn.GetFileSize("/full/or/relative/path/to/file")); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetWorkingDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class GetWorkingDirectoryExample { 7 | public static void GetWorkingDirectory() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | Console.WriteLine("The working directory is: "+ 12 | conn.GetWorkingDirectory()); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetModifiedTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class GetModifiedTimeExample { 7 | public static void GetModifiedTime() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | Console.WriteLine("The modified type is: "+ 12 | conn.GetModifiedTime("/full/or/relative/path/to/file")); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FluentFTP.Examples/DeleteDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class DeleteDirectoryExample { 7 | public static void DeleteDirectory() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | 12 | // Remove the directory and all objects beneath it. 13 | conn.DeleteDirectory("/path/to/directory"); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FluentFTP.Tests/XUnitShim.cs: -------------------------------------------------------------------------------- 1 | #if SHIM_XUNIT 2 | using System; 3 | 4 | namespace Xunit 5 | { 6 | public sealed class FactAttribute : Attribute { } 7 | public sealed class TheoryAttribute : Attribute { } 8 | public sealed class InlineDataAttribute : Attribute 9 | { 10 | public InlineDataAttribute(params object[] data) { } 11 | } 12 | public sealed class TraitAttribute : Attribute 13 | { 14 | public TraitAttribute(string name, string value) { } 15 | } 16 | 17 | public static class Assert 18 | { 19 | public static T Throws(Action testCode) where T : Exception => default(T); 20 | } 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /FluentFTP.Examples/SetHashAlgorithm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public class SetHashAlgorithmExample { 7 | public static void SetHashAlgorithm() { 8 | using (FtpClient cl = new FtpClient()) { 9 | cl.Credentials = new NetworkCredential("user", "pass"); 10 | cl.Host = "some.ftpserver.on.the.internet.com"; 11 | 12 | if (cl.HashAlgorithms.HasFlag(FtpHashAlgorithm.MD5)) 13 | cl.SetHashAlgorithm(FtpHashAlgorithm.MD5); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FluentFTP.Examples/DirectoryExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class DirectoryExistsExample { 7 | public static void DeleteDirectory() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | 12 | if (conn.DirectoryExists("/full/or/relative/path")) { 13 | // do something 14 | } 15 | 16 | 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetHashAlgorithm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public class GetHashAlgorithmExample { 7 | public static void GetHashAlgorithm() { 8 | using (FtpClient cl = new FtpClient()) { 9 | cl.Credentials = new NetworkCredential("user", "pass"); 10 | cl.Host = "some.ftpserver.on.the.internet.com"; 11 | 12 | Console.WriteLine("The server is using the following algorithm for computing hashes: "+ 13 | cl.GetHashAlgorithm()); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenWrite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using FluentFTP; 5 | 6 | namespace Examples { 7 | public class OpenWriteExample { 8 | public static void OpenWrite() { 9 | using (FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | 13 | using (Stream ostream = conn.OpenWrite("/full/or/relative/path/to/file")) { 14 | try { 15 | // istream.Position is incremented accordingly to the writes you perform 16 | } finally { 17 | ostream.Close(); 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/Execute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class ExecuteExample { 7 | public static void Execute() { 8 | using (FtpClient conn = new FtpClient()) { 9 | FtpReply reply; 10 | 11 | conn.Host = "localhost"; 12 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 13 | 14 | if (!(reply = conn.Execute("SITE CHMOD 640 FOO.TXT")).Success) { 15 | throw new FtpCommandException(reply); 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FluentFTP.Examples/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Examples { 4 | public static class Extensions { 5 | public static string FormatBytes(this long val) { 6 | return ((double)val).FormatBytes(); 7 | } 8 | 9 | public static string FormatBytes(this int val) { 10 | return ((double)val).FormatBytes(); 11 | } 12 | 13 | public static string FormatBytes(this double val) { 14 | string[] units = new string[] { "B", "KB", "MB", "GB", "TB" }; 15 | int count = 0; 16 | 17 | while (count + 1 < units.Length && val >= 1024) { 18 | count += 1; 19 | val /= 1024; 20 | } 21 | 22 | return string.Format("{0:0.00} {1}", val, units[count]); 23 | } 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /FluentFTP.Examples/Rename.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | 6 | namespace Examples { 7 | public static class RenameExample { 8 | public static void Rename() { 9 | using (FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | // renaming a directory is dependant on the server! if you attempt it 13 | // and it fails it's not because FluentFTP has a bug! 14 | conn.Rename("/full/or/relative/path/to/src", "/full/or/relative/path/to/dest"); 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FluentFTP.Examples/FileExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class FileExistsExample { 7 | public static void FileExists() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | 12 | // The last parameter forces FluentFTP to use LIST -a 13 | // for getting a list of objects in the parent directory. 14 | if (conn.FileExists("/full/or/relative/path")) { 15 | // dome something 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FluentFTP/Proxy/FtpClientProxy.cs: -------------------------------------------------------------------------------- 1 | namespace FluentFTP.Proxy { 2 | /// 3 | /// Abstraction of an FtpClient with a proxy 4 | /// 5 | public abstract class FtpClientProxy : FtpClient { 6 | private ProxyInfo _proxy; 7 | /// The proxy connection info. 8 | protected ProxyInfo Proxy { get { return _proxy; } } 9 | 10 | /// A FTP client with a HTTP 1.1 proxy implementation 11 | /// Proxy information 12 | protected FtpClientProxy(ProxyInfo proxy) { 13 | _proxy = proxy; 14 | } 15 | 16 | /// Redefine connect for FtpClient : authentication on the Proxy 17 | /// The socket stream. 18 | protected override void Connect(FtpSocketStream stream) { 19 | stream.Connect(Proxy.Host, Proxy.Port, InternetProtocolVersions); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenReadURI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public static class OpenReadURI { 7 | public static void OpenURI() { 8 | using (Stream s = FtpClient.OpenRead(new Uri("ftp://server/path/file"))) { 9 | byte[] buf = new byte[8192]; 10 | int read = 0; 11 | 12 | try { 13 | while ((read = s.Read(buf, 0, buf.Length)) > 0) { 14 | Console.Write("\r{0}/{1} {2:p} ", 15 | s.Position, s.Length, 16 | ((double)s.Position / (double)s.Length)); 17 | } 18 | } 19 | finally { 20 | Console.WriteLine(); 21 | s.Close(); 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetNameListing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | class GetNameListingExample { 7 | public static void GetNameListing() { 8 | using (FtpClient cl = new FtpClient()) { 9 | cl.Credentials = new NetworkCredential("ftp", "ftp"); 10 | cl.Host = "ftp.example.com"; 11 | cl.Connect(); 12 | 13 | foreach (string s in cl.GetNameListing()) { 14 | // load some information about the object 15 | // returned from the listing... 16 | bool isDirectory = cl.DirectoryExists(s); 17 | DateTime modify = cl.GetModifiedTime(s); 18 | long size = isDirectory ? 0 : cl.GetFileSize(s); 19 | 20 | 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /FluentFTP.Examples/ValidateCertificate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public static class ValidateCertificateExample { 7 | public static void ValidateCertificate() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | conn.EncryptionMode = FtpEncryptionMode.Explicit; 12 | conn.ValidateCertificate += new FtpSslValidation(OnValidateCertificate); 13 | conn.Connect(); 14 | } 15 | } 16 | 17 | static void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e) { 18 | if (e.PolicyErrors != System.Net.Security.SslPolicyErrors.None) { 19 | // invalid cert, do you want to accept it? 20 | // e.Accept = true; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 J.P. Trosclair 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /FluentFTP/Proxy/FtpClientUserAtHostProxy.cs: -------------------------------------------------------------------------------- 1 | namespace FluentFTP.Proxy { 2 | /// A FTP client with a user@host proxy identification. 3 | public class FtpClientUserAtHostProxy : FtpClientProxy { 4 | /// A FTP client with a user@host proxy identification. 5 | /// Proxy information 6 | public FtpClientUserAtHostProxy(ProxyInfo proxy) 7 | : base(proxy) { 8 | ConnectionType = "User@Host"; 9 | } 10 | 11 | /// 12 | /// Creates a new instance of this class. Useful in FTP proxy classes. 13 | /// 14 | protected override FtpClient Create() { 15 | return new FtpClientUserAtHostProxy(Proxy); 16 | } 17 | 18 | /// Redefine the first dialog: auth with proxy information 19 | protected override void Handshake() { 20 | // Proxy authentication eventually needed. 21 | if (Proxy.Credentials != null) 22 | Authenticate(Proxy.Credentials.UserName, Proxy.Credentials.Password); 23 | 24 | // Connection USER@Host means to change user name to add host. 25 | Credentials.UserName = Credentials.UserName + "@" + Host; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenRead.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using FluentFTP; 5 | 6 | namespace Examples { 7 | public class OpenReadExample { 8 | public static void OpenRead() { 9 | using(FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | 13 | using(Stream istream = conn.OpenRead("/full/or/relative/path/to/file")) { 14 | try { 15 | // istream.Position is incremented accordingly to the reads you perform 16 | // istream.Length == file size if the server supports getting the file size 17 | // also note that file size for the same file can vary between ASCII and Binary 18 | // modes and some servers won't even give a file size for ASCII files! It is 19 | // recommended that you stick with Binary and worry about character encodings 20 | // on your end of the connection. 21 | } 22 | finally { 23 | Console.WriteLine(); 24 | istream.Close(); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /FluentFTP.Examples/SetEncryptionProtocols.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Security.Authentication; 5 | 6 | namespace Examples 7 | { 8 | public static class SetEncryptionProtocolsExample { 9 | public static void ValidateCertificate() 10 | { 11 | using (FtpClient conn = new FtpClient()) 12 | { 13 | conn.Host = "localhost"; 14 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 15 | conn.EncryptionMode = FtpEncryptionMode.Explicit; 16 | 17 | // Override the default protocols. The example line sets the protocols 18 | // to support TLS 1.1 and TLS 1.2. These are only available if the 19 | // executable targets .NET 4.5 (or higher). The framework does not enable these 20 | // protocols by default. 21 | //conn.SslProtocols = SslProtocols.Default | SslProtocols.Tls11 | SslProtocols.Tls12; 22 | 23 | // Alternate example: Only support the latest level. 24 | //conn.SslProtocols = SslProtocols.Tls12; 25 | 26 | conn.Connect(); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetChecksum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public static class GetChecksumExample { 7 | public static void GetChceksumExample() { 8 | FtpHash hash = null; 9 | 10 | using (FtpClient cl = new FtpClient()) { 11 | cl.Credentials = new NetworkCredential("user", "pass"); 12 | cl.Host = "some.ftpserver.on.the.internet.com"; 13 | 14 | hash = cl.GetChecksum("/path/to/remote/file"); 15 | // Make sure it returned a, to the best of our knowledge, valid 16 | // hash object. The commands for retrieving checksums are 17 | // non-standard extensions to the protocol so we have to 18 | // presume that the response was in a format understood by 19 | // FluentFTP and parsed correctly. 20 | // 21 | // In addition, there is no built-in support for verifying 22 | // CRC hashes. You will need to write you own or use a 23 | // third-party solution. 24 | if (hash.IsValid && hash.Algorithm != FtpHashAlgorithm.CRC) { 25 | if (hash.Verify("/some/local/file")) { 26 | Console.WriteLine("The checksum's match!"); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FluentFTP.Examples/OpenAppend.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using FluentFTP; 5 | 6 | namespace Examples { 7 | public class OpenAppendExample { 8 | public static void OpenAppend() { 9 | using (FtpClient conn = new FtpClient()) { 10 | conn.Host = "localhost"; 11 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 12 | 13 | using (Stream ostream = conn.OpenAppend("/full/or/relative/path/to/file")) { 14 | try { 15 | // be sure to seek your output stream to the appropriate location, i.e., istream.Position 16 | // istream.Position is incremented accordingly to the writes you perform 17 | // istream.Position == file size if the server supports getting the file size 18 | // also note that file size for the same file can vary between ASCII and Binary 19 | // modes and some servers won't even give a file size for ASCII files! It is 20 | // recommended that you stick with Binary and worry about character encodings 21 | // on your end of the connection. 22 | } 23 | finally { 24 | ostream.Close(); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginConnect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginConnectExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginConnect() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginConnect(new AsyncCallback(ConnectCallback), conn); 21 | 22 | m_reset.WaitOne(); 23 | conn.Disconnect(); 24 | } 25 | } 26 | 27 | static void ConnectCallback(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | conn.EndConnect(ar); 35 | } 36 | catch (Exception ex) { 37 | Console.WriteLine(ex.ToString()); 38 | } 39 | finally { 40 | m_reset.Set(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FluentFTP.Examples/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Examples { 5 | class MainClass { 6 | public static void Main(string[] args) { 7 | Debug.Listeners.Add(new ConsoleTraceListener()); 8 | 9 | try { 10 | //BeginConnectExample.BeginConnect(); 11 | //BeginCreateDirectoryExample.BeginCreateDirectory(); 12 | //BeginDeleteDirectoryExample.BeginDeleteDirectory(); 13 | //BeginDeleteFileExample.BeginDeleteFile(); 14 | //BeginDirectoryExistsExample.BeginDirectoryExists(); 15 | //BeginDisconnectExample.BeginDisconnect(); 16 | //BeginDownloadExample.BeginDownload(); 17 | //BeginExecuteExample.BeginExecute(); 18 | //BeginFileExistsExample.BeginFileExists(); 19 | //BeginGetFileSizeExample.BeginGetFileSize(); 20 | //BeginGetListing.BeginGetListingExample(); 21 | //BeginGetModifiedTimeExample.BeginGetModifiedTime(); 22 | //BeginGetWorkingDirectoryExample.BeginGetWorkingDirectory(); 23 | //BeginRenameExample.BeginRename(); 24 | //BeginSetDataTypeExample.BeginSetDataType(); 25 | //BeginSetWorkingDirectoryExample.BeginSetWorkingDirectory(); 26 | //OpenReadURI.OpenURI(); 27 | //BeginGetNameListingExample.BeginGetNameListing(); 28 | } 29 | catch (Exception ex) { 30 | Console.WriteLine(ex.ToString()); 31 | } 32 | 33 | //Console.WriteLine("--DONE--"); 34 | Console.ReadKey(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginDisconnect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginDisconnectExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginDisconnect() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginDisconnect(new AsyncCallback(BeginDisconnectCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | } 25 | } 26 | 27 | static void BeginDisconnectCallback(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | conn.EndDisconnect(ar); 35 | } 36 | catch (Exception ex) { 37 | Console.WriteLine(ex.ToString()); 38 | } 39 | finally { 40 | m_reset.Set(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginDeleteFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginDeleteFileExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginDeleteFile() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginDeleteFile("/path/to/file", new AsyncCallback(DeleteFileCallback), conn); 21 | 22 | m_reset.WaitOne(); 23 | conn.Disconnect(); 24 | } 25 | } 26 | 27 | static void DeleteFileCallback(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | conn.EndDeleteFile(ar); 35 | } 36 | catch (Exception ex) { 37 | Console.WriteLine(ex.ToString()); 38 | } 39 | finally { 40 | m_reset.Set(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginRename.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginRenameExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginRename() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginRename("/source/object", "/new/path/and/name", 21 | new AsyncCallback(BeginRenameCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginRenameCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | conn.EndRename(ar); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginSetWorkingDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginSetWorkingDirectoryExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginSetWorkingDirectory() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginSetWorkingDirectory("/", new AsyncCallback(BeginSetWorkingDirectoryCallback), conn); 21 | 22 | m_reset.WaitOne(); 23 | conn.Disconnect(); 24 | } 25 | } 26 | 27 | static void BeginSetWorkingDirectoryCallback(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | conn.EndSetWorkingDirectory(ar); 35 | } 36 | catch (Exception ex) { 37 | Console.WriteLine(ex.ToString()); 38 | } 39 | finally { 40 | m_reset.Set(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginDeleteDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | class BeginDeleteDirectoryExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginDeleteDirectory() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.CreateDirectory("/some/test/directory"); 21 | conn.BeginDeleteDirectory("/some", new AsyncCallback(DeleteDirectoryCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void DeleteDirectoryCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | conn.EndDeleteDirectory(ar); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginFileExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginFileExistsExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginFileExists() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginFileExists("foobar", new AsyncCallback(BeginFileExistsCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginFileExistsCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | Console.WriteLine("File exists: "+ conn.EndFileExists(ar)); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginDirectoryExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginDirectoryExistsExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginDirectoryExists() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginDirectoryExists("/path/to/directory", new AsyncCallback(DirectoryExistsCallback), conn); 21 | 22 | m_reset.WaitOne(); 23 | conn.Disconnect(); 24 | } 25 | } 26 | 27 | static void DirectoryExistsCallback(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | Console.WriteLine("Directory Exiss: "+ conn.EndDirectoryExists(ar)); 35 | } 36 | catch (Exception ex) { 37 | Console.WriteLine(ex.ToString()); 38 | } 39 | finally { 40 | m_reset.Set(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginGetFileSize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginGetFileSizeExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginGetFileSize() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginGetFileSize("foobar", new AsyncCallback(BeginGetFileSizeCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginGetFileSizeCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | Console.WriteLine("File size: "+ conn.EndGetFileSize(ar)); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginGetModifiedTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginGetModifiedTimeExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginGetModifiedTime() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginGetModifiedTime("foobar", FtpDate.UTC, new AsyncCallback(BeginGetModifiedTimeCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginGetModifiedTimeCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | Console.WriteLine("Modify time: "+ conn.EndGetModifiedTime(ar)); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginGetWorkingDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginGetWorkingDirectoryExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginGetWorkingDirectory() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginGetWorkingDirectory(new AsyncCallback(BeginGetWorkingDirectoryCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginGetWorkingDirectoryCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | 31 | try { 32 | if (conn == null) 33 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 34 | 35 | Console.WriteLine("Working directory: "+ conn.EndGetWorkingDirectory(ar)); 36 | } 37 | catch (Exception ex) { 38 | Console.WriteLine(ex.ToString()); 39 | } 40 | finally { 41 | m_reset.Set(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginCreateDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.IO; 4 | using System.Net; 5 | using FluentFTP; 6 | 7 | namespace Examples { 8 | public static class BeginCreateDirectoryExample { 9 | static ManualResetEvent m_reset = new ManualResetEvent(false); 10 | 11 | public static void BeginCreateDirectory() { 12 | // The using statement here is OK _only_ because m_reset.WaitOne() 13 | // causes the code to block until the async process finishes, otherwise 14 | // the connection object would be disposed early. In practice, you 15 | // typically would not wrap the following code with a using statement. 16 | using (FtpClient conn = new FtpClient()) { 17 | m_reset.Reset(); 18 | 19 | conn.Host = "localhost"; 20 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 21 | conn.DeleteDirectory("/test"); 22 | conn.BeginCreateDirectory("/test/path/that/should/be/created", true, 23 | new AsyncCallback(CreateDirectoryCallback), conn); 24 | 25 | m_reset.WaitOne(); 26 | conn.Disconnect(); 27 | } 28 | } 29 | 30 | static void CreateDirectoryCallback(IAsyncResult ar) { 31 | FtpClient conn = ar.AsyncState as FtpClient; 32 | 33 | try { 34 | if (conn == null) 35 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 36 | 37 | conn.EndCreateDirectory(ar); 38 | } 39 | catch (Exception ex) { 40 | Console.WriteLine(ex.ToString()); 41 | } 42 | finally { 43 | m_reset.Set(); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginExecute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public class BeginExecuteExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginExecute() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.Connect(); 21 | conn.BeginExecute("SYST", new AsyncCallback(BeginExecuteCallback), conn); 22 | 23 | m_reset.WaitOne(); 24 | conn.Disconnect(); 25 | } 26 | } 27 | 28 | static void BeginExecuteCallback(IAsyncResult ar) { 29 | FtpClient conn = ar.AsyncState as FtpClient; 30 | FtpReply reply; 31 | 32 | try { 33 | if (conn == null) 34 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 35 | 36 | reply = conn.EndExecute(ar); 37 | if (!reply.Success) 38 | throw new FtpCommandException(reply); 39 | 40 | Console.WriteLine(reply.Message); 41 | } 42 | catch (Exception ex) { 43 | Console.WriteLine(ex.ToString()); 44 | } 45 | finally { 46 | m_reset.Set(); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginGetListing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | // Also see the GetListing() example for more details 8 | // about file listings and the objects returned. 9 | public static class BeginGetListing { 10 | static ManualResetEvent m_reset = new ManualResetEvent(false); 11 | 12 | public static void BeginGetListingExample() { 13 | // The using statement here is OK _only_ because m_reset.WaitOne() 14 | // causes the code to block until the async process finishes, otherwise 15 | // the connection object would be disposed early. In practice, you 16 | // typically would not wrap the following code with a using statement. 17 | using (FtpClient conn = new FtpClient()) { 18 | m_reset.Reset(); 19 | 20 | conn.Host = "localhost"; 21 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 22 | conn.Connect(); 23 | conn.BeginGetListing(new AsyncCallback(GetListingCallback), conn); 24 | 25 | m_reset.WaitOne(); 26 | conn.Disconnect(); 27 | } 28 | } 29 | 30 | static void GetListingCallback(IAsyncResult ar) { 31 | FtpClient conn = ar.AsyncState as FtpClient; 32 | 33 | try { 34 | if (conn == null) 35 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 36 | 37 | foreach (FtpListItem item in conn.EndGetListing(ar)) 38 | Console.WriteLine(item); 39 | } 40 | catch (Exception ex) { 41 | Console.WriteLine(ex.ToString()); 42 | } 43 | finally { 44 | m_reset.Set(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /FluentFTP.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.4 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentFTP", "FluentFTP\FluentFTP.csproj", "{117F9BA2-711B-4C71-92EC-002220B157DD}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "FluentFTP.Examples\Examples.csproj", "{49B11591-C942-479F-A864-AB2738E50EF0}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "FluentFTP.Tests\Tests.csproj", "{28AA032E-CACF-4C07-BF12-C4FBE71BC8BD}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {117F9BA2-711B-4C71-92EC-002220B157DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {117F9BA2-711B-4C71-92EC-002220B157DD}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {117F9BA2-711B-4C71-92EC-002220B157DD}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {117F9BA2-711B-4C71-92EC-002220B157DD}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {49B11591-C942-479F-A864-AB2738E50EF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {49B11591-C942-479F-A864-AB2738E50EF0}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {49B11591-C942-479F-A864-AB2738E50EF0}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {49B11591-C942-479F-A864-AB2738E50EF0}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {28AA032E-CACF-4C07-BF12-C4FBE71BC8BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {28AA032E-CACF-4C07-BF12-C4FBE71BC8BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {28AA032E-CACF-4C07-BF12-C4FBE71BC8BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {28AA032E-CACF-4C07-BF12-C4FBE71BC8BD}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginGetNameListing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.Threading; 5 | 6 | namespace Examples { 7 | public static class BeginGetNameListingExample { 8 | static ManualResetEvent m_reset = new ManualResetEvent(false); 9 | 10 | public static void BeginGetNameListing() { 11 | // The using statement here is OK _only_ because m_reset.WaitOne() 12 | // causes the code to block until the async process finishes, otherwise 13 | // the connection object would be disposed early. In practice, you 14 | // typically would not wrap the following code with a using statement. 15 | using (FtpClient conn = new FtpClient()) { 16 | m_reset.Reset(); 17 | 18 | conn.Host = "localhost"; 19 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 20 | conn.BeginGetNameListing(new AsyncCallback(EndGetNameListing), conn); 21 | 22 | m_reset.WaitOne(); 23 | conn.Disconnect(); 24 | } 25 | } 26 | 27 | static void EndGetNameListing(IAsyncResult ar) { 28 | FtpClient conn = ar.AsyncState as FtpClient; 29 | 30 | try { 31 | if (conn == null) 32 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 33 | 34 | foreach (string s in conn.EndGetNameListing(ar)) { 35 | // load some information about the object 36 | // returned from the listing... 37 | bool isDirectory = conn.DirectoryExists(s); 38 | DateTime modify = conn.GetModifiedTime(s); 39 | long size = isDirectory ? 0 : conn.GetFileSize(s); 40 | } 41 | } 42 | catch (Exception ex) { 43 | Console.WriteLine(ex.ToString()); 44 | } 45 | finally { 46 | m_reset.Set(); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | public class GetHashExample { 7 | public static void GetHash() { 8 | using (FtpClient cl = new FtpClient()) { 9 | cl.Credentials = new NetworkCredential("user", "pass"); 10 | cl.Host = "some.ftpserver.on.the.internet.com"; 11 | 12 | // If server supports the HASH command then the 13 | // FtpClient.HashAlgorithms flags will NOT be equal 14 | // to FtpHashAlgorithm.NONE. 15 | if (cl.HashAlgorithms != FtpHashAlgorithm.NONE) { 16 | FtpHash hash; 17 | 18 | // Ask the server to compute the hash using whatever 19 | // the default hash algorithm (probably SHA-1) on the 20 | // server is. 21 | hash = cl.GetHash("/path/to/remote/somefile.ext"); 22 | 23 | // The FtpHash.Verify method computes the hash of the 24 | // specified file or stream based on the hash algorithm 25 | // the server computed its hash with. The classes used 26 | // for computing the local hash are part of the .net 27 | // framework, located in the System.Security.Cryptography 28 | // namespace and are derived from 29 | // System.Security.Cryptography.HashAlgorithm. 30 | if (hash.Verify("/path/to/local/somefile.ext")) { 31 | Console.WriteLine("The computed hashes match!"); 32 | } 33 | 34 | // Manually specify the hash algorithm to use. 35 | if (cl.HashAlgorithms.HasFlag(FtpHashAlgorithm.MD5)) { 36 | cl.SetHashAlgorithm(FtpHashAlgorithm.MD5); 37 | hash = cl.GetHash("/path/to/remote/somefile.ext"); 38 | if (hash.Verify("/path/to/local/somefile.ext")) { 39 | Console.WriteLine("The computed hashes match!"); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginOpenWrite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | using System.Threading; 6 | 7 | namespace Examples { 8 | public static class BeginOpenWriteExample { 9 | static ManualResetEvent m_reset = new ManualResetEvent(false); 10 | 11 | public static void BeginOpenWrite() { 12 | // The using statement here is OK _only_ because m_reset.WaitOne() 13 | // causes the code to block until the async process finishes, otherwise 14 | // the connection object would be disposed early. In practice, you 15 | // typically would not wrap the following code with a using statement. 16 | using (FtpClient conn = new FtpClient()) { 17 | m_reset.Reset(); 18 | 19 | conn.Host = "localhost"; 20 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 21 | conn.BeginOpenWrite("/path/to/file", 22 | new AsyncCallback(BeginOpenWriteCallback), conn); 23 | 24 | m_reset.WaitOne(); 25 | conn.Disconnect(); 26 | } 27 | } 28 | 29 | static void BeginOpenWriteCallback(IAsyncResult ar) { 30 | FtpClient conn = ar.AsyncState as FtpClient; 31 | Stream istream = null, ostream = null; 32 | byte[] buf = new byte[8192]; 33 | int read = 0; 34 | 35 | try { 36 | if (conn == null) 37 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 38 | 39 | ostream = conn.EndOpenWrite(ar); 40 | istream = new FileStream("input_file", FileMode.Open, FileAccess.Read); 41 | 42 | while ((read = istream.Read(buf, 0, buf.Length)) > 0) { 43 | ostream.Write(buf, 0, read); 44 | } 45 | } 46 | catch (Exception ex) { 47 | Console.WriteLine(ex.ToString()); 48 | } 49 | finally { 50 | if (istream != null) 51 | istream.Close(); 52 | 53 | if (ostream != null) 54 | ostream.Close(); 55 | 56 | m_reset.Set(); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginOpenAppend.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | using System.Threading; 6 | 7 | namespace Examples { 8 | public static class BeginOpenAppendExample { 9 | static ManualResetEvent m_reset = new ManualResetEvent(false); 10 | 11 | public static void BeginOpenAppend() { 12 | // The using statement here is OK _only_ because m_reset.WaitOne() 13 | // causes the code to block until the async process finishes, otherwise 14 | // the connection object would be disposed early. In practice, you 15 | // typically would not wrap the following code with a using statement. 16 | using (FtpClient conn = new FtpClient()) { 17 | m_reset.Reset(); 18 | 19 | conn.Host = "localhost"; 20 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 21 | conn.BeginOpenAppend("/path/to/file", 22 | new AsyncCallback(BeginOpenAppendCallback), conn); 23 | 24 | m_reset.WaitOne(); 25 | conn.Disconnect(); 26 | } 27 | } 28 | 29 | static void BeginOpenAppendCallback(IAsyncResult ar) { 30 | FtpClient conn = ar.AsyncState as FtpClient; 31 | Stream istream = null, ostream = null; 32 | byte[] buf = new byte[8192]; 33 | int read = 0; 34 | 35 | try { 36 | if (conn == null) 37 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 38 | 39 | ostream = conn.EndOpenAppend(ar); 40 | istream = new FileStream("input_file", FileMode.Open, FileAccess.Read); 41 | 42 | while ((read = istream.Read(buf, 0, buf.Length)) > 0) { 43 | ostream.Write(buf, 0, read); 44 | } 45 | } 46 | catch (Exception ex) { 47 | Console.WriteLine(ex.ToString()); 48 | } 49 | finally { 50 | if (istream != null) 51 | istream.Close(); 52 | 53 | if (ostream != null) 54 | ostream.Close(); 55 | 56 | m_reset.Set(); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /FluentFTP.Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net452;netstandard1.4;netstandard1.6;netcoreapp1.0;net20;net35;net40;net45 5 | 6 | 7 | 8 | $(DefineConstants);SHIM_XUNIT 9 | 10 | 11 | 12 | $(DefineConstants);NOASYNC 13 | 14 | 15 | 16 | $(DefineConstants);CORE 17 | 18 | 19 | 20 | $(DefineConstants);CORE14 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | PreserveNewest 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /FluentFTP.Examples/GetListing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class GetListingExample { 7 | public static void GetListing() { 8 | using (FtpClient conn = new FtpClient()) { 9 | conn.Host = "localhost"; 10 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 11 | 12 | foreach (FtpListItem item in conn.GetListing(conn.GetWorkingDirectory(), 13 | FtpListOption.Modify | FtpListOption.Size)) { 14 | 15 | switch (item.Type) { 16 | case FtpFileSystemObjectType.Directory: 17 | break; 18 | case FtpFileSystemObjectType.File: 19 | break; 20 | case FtpFileSystemObjectType.Link: 21 | // derefernece symbolic links 22 | if (item.LinkTarget != null) { 23 | // see the DereferenceLink() example 24 | // for more details about resolving links. 25 | item.LinkObject = conn.DereferenceLink(item); 26 | 27 | if (item.LinkObject != null) { 28 | // switch (item.LinkObject.Type)... 29 | } 30 | } 31 | break; 32 | } 33 | } 34 | 35 | // same example except automatically dereference symbolic links. 36 | // see the DereferenceLink() example for more details about resolving links. 37 | foreach (FtpListItem item in conn.GetListing(conn.GetWorkingDirectory(), 38 | FtpListOption.Modify | FtpListOption.Size | FtpListOption.DerefLinks)) { 39 | 40 | switch (item.Type) { 41 | case FtpFileSystemObjectType.Directory: 42 | break; 43 | case FtpFileSystemObjectType.File: 44 | break; 45 | case FtpFileSystemObjectType.Link: 46 | if (item.LinkObject != null) { 47 | // switch (item.LinkObject.Type)... 48 | } 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginDereferenceLink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Threading; 4 | using FluentFTP; 5 | 6 | namespace Examples { 7 | /// 8 | /// This example illustrates how to dereference a symbolic link asyncrhonously. The 9 | /// code bollow takes a FtpListItem object and checks if it is a symbolic link and 10 | /// that the LinkTarget property has been initalized before executing the method. Not 11 | /// doing so can result in a FtpException being thrown. 12 | /// 13 | /// Also see the DerefenceLink() example! There is lots of information 14 | /// not mentioned here! 15 | /// 16 | static class BeginDereferenceLink { 17 | static ManualResetEvent m_reset = new ManualResetEvent(false); 18 | 19 | public static void BeginDereferenceLinkExample(FtpListItem item) { 20 | // The using statement here is OK _only_ because m_reset.WaitOne() 21 | // causes the code to block until the async process finishes, otherwise 22 | // the connection object would be disposed early. In practice, you 23 | // typically would not wrap the following code with a using statement. 24 | using (FtpClient conn = new FtpClient()) { 25 | m_reset.Reset(); 26 | 27 | conn.Host = "localhost"; 28 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 29 | conn.Connect(); 30 | 31 | if (item.Type == FtpFileSystemObjectType.Link && item.LinkTarget != null) { 32 | conn.BeginDereferenceLink(item, new AsyncCallback(DereferenceLinkCallback), conn); 33 | m_reset.WaitOne(); 34 | } 35 | 36 | conn.Disconnect(); 37 | } 38 | } 39 | 40 | static void DereferenceLinkCallback(IAsyncResult ar) { 41 | FtpClient conn = ar.AsyncState as FtpClient; 42 | FtpListItem target; 43 | 44 | try { 45 | if (conn == null) 46 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 47 | 48 | target = conn.EndDereferenceLink(ar); 49 | if (target != null) { 50 | // success... 51 | } 52 | } 53 | catch (Exception ex) { 54 | Console.WriteLine(ex.ToString()); 55 | } 56 | finally { 57 | m_reset.Set(); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Sockets; 4 | using System.Net.Security; 5 | using System.Security.Authentication; 6 | using System.Security.Cryptography.X509Certificates; 7 | using System.Threading; 8 | using System.Collections.Generic; 9 | using System.Diagnostics; 10 | using System.Net; 11 | 12 | #if NET45 13 | using System.Threading.Tasks; 14 | #endif 15 | 16 | namespace FluentFTP { 17 | 18 | /// 19 | /// Event is fired when a SSL certificate needs to be validated 20 | /// 21 | /// The control connection that triggered the event 22 | /// Event args 23 | public delegate void FtpSslValidation(FtpClient control, FtpSslValidationEventArgs e); 24 | 25 | /// 26 | /// Event fired if a bad SSL certificate is encountered. This even is used internally; if you 27 | /// don't have a specific reason for using it you are probably looking for FtpSslValidation. 28 | /// 29 | /// 30 | /// 31 | public delegate void FtpSocketStreamSslValidation(FtpSocketStream stream, FtpSslValidationEventArgs e); 32 | 33 | /// 34 | /// Event args for the FtpSslValidationError delegate 35 | /// 36 | public class FtpSslValidationEventArgs : EventArgs { 37 | X509Certificate m_certificate = null; 38 | /// 39 | /// The certificate to be validated 40 | /// 41 | public X509Certificate Certificate { 42 | get { 43 | return m_certificate; 44 | } 45 | set { 46 | m_certificate = value; 47 | } 48 | } 49 | 50 | X509Chain m_chain = null; 51 | /// 52 | /// The certificate chain 53 | /// 54 | public X509Chain Chain { 55 | get { 56 | return m_chain; 57 | } 58 | set { 59 | m_chain = value; 60 | } 61 | } 62 | 63 | SslPolicyErrors m_policyErrors = SslPolicyErrors.None; 64 | /// 65 | /// Validation errors, if any. 66 | /// 67 | public SslPolicyErrors PolicyErrors { 68 | get { 69 | return m_policyErrors; 70 | } 71 | set { 72 | m_policyErrors = value; 73 | } 74 | } 75 | 76 | bool m_accept = false; 77 | /// 78 | /// Gets or sets a value indicating if this certificate should be accepted. The default 79 | /// value is false. If the certificate is not accepted, an AuthenticationException will 80 | /// be thrown. 81 | /// 82 | public bool Accept { 83 | get { 84 | return m_accept; 85 | } 86 | set { 87 | m_accept = value; 88 | } 89 | } 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/BeginOpenRead.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | using System.IO; 5 | using System.Threading; 6 | 7 | namespace Examples { 8 | public static class BeginOpenReadExample { 9 | static ManualResetEvent m_reset = new ManualResetEvent(false); 10 | 11 | public static void BeginOpenRead() { 12 | // The using statement here is OK _only_ because m_reset.WaitOne() 13 | // causes the code to block until the async process finishes, otherwise 14 | // the connection object would be disposed early. In practice, you 15 | // typically would not wrap the following code with a using statement. 16 | using (FtpClient conn = new FtpClient()) { 17 | m_reset.Reset(); 18 | 19 | conn.Host = "localhost"; 20 | conn.Credentials = new NetworkCredential("ftptest", "ftptest"); 21 | conn.BeginOpenRead("/path/to/file", 22 | new AsyncCallback(BeginOpenReadCallback), conn); 23 | 24 | m_reset.WaitOne(); 25 | conn.Disconnect(); 26 | } 27 | } 28 | 29 | static void BeginOpenReadCallback(IAsyncResult ar) { 30 | FtpClient conn = ar.AsyncState as FtpClient; 31 | 32 | try { 33 | if (conn == null) 34 | throw new InvalidOperationException("The FtpControlConnection object is null!"); 35 | 36 | using (Stream istream = conn.EndOpenRead(ar)) { 37 | byte[] buf = new byte[8192]; 38 | 39 | try { 40 | DateTime start = DateTime.Now; 41 | 42 | while (istream.Read(buf, 0, buf.Length) > 0) { 43 | double perc = 0; 44 | 45 | if (istream.Length > 0) 46 | perc = (double)istream.Position / (double)istream.Length; 47 | 48 | Console.Write("\rTransferring: {0}/{1} {2}/s {3:p} ", 49 | istream.Position.FormatBytes(), 50 | istream.Length.FormatBytes(), 51 | (istream.Position / DateTime.Now.Subtract(start).TotalSeconds).FormatBytes(), 52 | perc); 53 | } 54 | } 55 | finally { 56 | Console.WriteLine(); 57 | istream.Close(); 58 | } 59 | } 60 | } 61 | catch (Exception ex) { 62 | Console.WriteLine(ex.ToString()); 63 | } 64 | finally { 65 | m_reset.Set(); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpReply.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace FluentFTP { 6 | /// 7 | /// Represents a reply to an event on the server 8 | /// 9 | public struct FtpReply { 10 | /// 11 | /// The type of response received from the last command executed 12 | /// 13 | public FtpResponseType Type { 14 | get { 15 | int code; 16 | 17 | if (Code != null && Code.Length > 0 && 18 | int.TryParse(Code[0].ToString(), out code)) { 19 | return (FtpResponseType)code; 20 | } 21 | 22 | return FtpResponseType.None; 23 | } 24 | } 25 | 26 | string m_respCode; 27 | /// 28 | /// The status code of the response 29 | /// 30 | public string Code { 31 | get { 32 | return m_respCode; 33 | } 34 | set { 35 | m_respCode = value; 36 | } 37 | } 38 | 39 | string m_respMessage; 40 | /// 41 | /// The message, if any, that the server sent with the response 42 | /// 43 | public string Message { 44 | get { 45 | return m_respMessage; 46 | } 47 | set { 48 | m_respMessage = value; 49 | } 50 | } 51 | 52 | string m_infoMessages; 53 | /// 54 | /// Informational messages sent from the server 55 | /// 56 | public string InfoMessages { 57 | get { 58 | return m_infoMessages; 59 | } 60 | set { 61 | m_infoMessages = value; 62 | } 63 | } 64 | 65 | /// 66 | /// General success or failure of the last command executed 67 | /// 68 | public bool Success { 69 | get { 70 | if (Code != null && Code.Length > 0) { 71 | int i; 72 | 73 | // 1xx, 2xx, 3xx indicate success 74 | // 4xx, 5xx are failures 75 | if (int.TryParse(Code[0].ToString(), out i) && i >= 1 && i <= 3) { 76 | return true; 77 | } 78 | } 79 | 80 | return false; 81 | } 82 | } 83 | 84 | /// 85 | /// Gets the error message including any informational output 86 | /// that was sent by the server. Sometimes the final response 87 | /// line doesn't contain anything informative as to what was going 88 | /// on with the server. Instead it may send information messages so 89 | /// in an effort to give as meaningful as a response as possible 90 | /// the informational messages will be included in the error. 91 | /// 92 | public string ErrorMessage { 93 | get { 94 | string message = ""; 95 | 96 | if (Success) { 97 | return message; 98 | } 99 | 100 | if (InfoMessages != null && InfoMessages.Length > 0) { 101 | foreach (string s in InfoMessages.Split('\n')) { 102 | string m = Regex.Replace(s, "^[0-9]{3}-", ""); 103 | message += (m.Trim() + "; "); 104 | } 105 | } 106 | 107 | message += Message; 108 | 109 | return message; 110 | } 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /FluentFTP/FluentFTP.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net20;net35;net40;net45;netstandard1.4;netstandard1.6 5 | 6 | 7 | 8 | $(DefineConstants);NETFX 9 | true 10 | 11 | 12 | 13 | $(DefineConstants);LINQBRIDGE_LIB 14 | 15 | 16 | 17 | $(DefineConstants);CORE 18 | 19 | 20 | 21 | $(DefineConstants);CORE14;NO_SSL 22 | 23 | 24 | 25 | $(DefineConstants);ASYNC 26 | 27 | 28 | 29 | FluentFTP 30 | FluentFTP 31 | An FTP and FTPS client for .NET & .NET Standard, optimized for speed. Provides extensive FTP commands, File uploads/downloads, SSL/TLS connections, Automatic directory listing parsing, File hashing/checksums, File permissions/CHMOD, FTP proxies, UTF-8 support, Async/await support and more. Written entirely in C#, with no external dependencies. 32 | Robin Rodricks, J.P. Trosclair, FluentFTP Contributors 33 | https://github.com/robinrodricks/FluentFTP/blob/master/LICENSE.TXT 34 | https://github.com/robinrodricks/FluentFTP 35 | MIT License 36 | ftp,ftp-client,ftps,ssl,tls,unix,iis 37 | 19.0.0 38 | bin\$(Configuration)\$(TargetFramework)\FluentFTP.xml 39 | True 40 | sn.snk 41 | 42 | 43 | 44 | True 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /FluentFTP.Examples/Debug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | /// 7 | /// Example for logging server transactions for use in debugging problems. 8 | /// 9 | public static class DebugExample { 10 | /// 11 | /// Log to a console window 12 | /// 13 | static void LogToConsole() { 14 | FtpTrace.AddListener(new ConsoleTraceListener()); 15 | 16 | // now use System.Net.FtpCLient as usual and the server transactions 17 | // will be written to the Console window. 18 | } 19 | 20 | /// 21 | /// Log to a text file 22 | /// 23 | static void LogToFile() { 24 | FtpTrace.AddListener(new TextWriterTraceListener("log_file.txt")); 25 | 26 | // now use System.Net.FtpCLient as usual and the server transactions 27 | // will be written to the specified log file. 28 | } 29 | 30 | /// 31 | /// Custom trace listener class that can log the transaction 32 | /// however you want. 33 | /// 34 | class CustomTraceListener : TraceListener { 35 | public override void Write(string message) { 36 | Console.Write(message); 37 | } 38 | 39 | public override void WriteLine(string message) { 40 | Console.WriteLine(message); 41 | } 42 | } 43 | 44 | /// 45 | /// Log to a custom TraceListener 46 | /// 47 | static void LogToCustomListener() { 48 | FtpTrace.AddListener(new CustomTraceListener()); 49 | } 50 | 51 | //Listeners can also be attached via app.config, web.config, or machine.config files 52 | /* 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 76 | * 77 | * 78 | * 79 | * 80 | * 83 | * 84 | * 85 | */ 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /FluentFTP/Utils/FtpReflection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | #if !CORE 5 | using System.Reflection; 6 | using System.Linq; 7 | #endif 8 | 9 | namespace FluentFTP { 10 | internal static class FtpReflection { 11 | 12 | #if !CORE 13 | public static object GetField(this object obj, string fieldName) { 14 | var tp = obj.GetType(); 15 | var info = GetAllFields(tp).Where(f => f.Name == fieldName).Single(); 16 | return info.GetValue(obj); 17 | } 18 | public static void SetField(this object obj, string fieldName, object value) { 19 | var tp = obj.GetType(); 20 | var info = GetAllFields(tp).Where(f => f.Name == fieldName).Single(); 21 | info.SetValue(obj, value); 22 | } 23 | public static object GetStaticField(this Assembly assembly, string typeName, string fieldName) { 24 | var tp = assembly.GetType(typeName); 25 | var info = GetAllFields(tp).Where(f => f.IsStatic).Where(f => f.Name == fieldName).Single(); 26 | return info.GetValue(null); 27 | } 28 | 29 | public static object GetProperty(this object obj, string propertyName) { 30 | var tp = obj.GetType(); 31 | var info = GetAllProperties(tp).Where(f => f.Name == propertyName).Single(); 32 | return info.GetValue(obj, null); 33 | } 34 | public static object CallMethod(this object obj, string methodName, params object[] prm) { 35 | var tp = obj.GetType(); 36 | var info = GetAllMethods(tp).Where(f => f.Name == methodName && f.GetParameters().Length == prm.Length).Single(); 37 | object rez = info.Invoke(obj, prm); 38 | return rez; 39 | } 40 | public static object NewInstance(this Assembly assembly, string typeName, params object[] prm) { 41 | var tp = assembly.GetType(typeName); 42 | var info = tp.GetConstructors().Where(f => f.GetParameters().Length == prm.Length).Single(); 43 | object rez = info.Invoke(prm); 44 | return rez; 45 | } 46 | public static object InvokeStaticMethod(this Assembly assembly, string typeName, string methodName, params object[] prm) { 47 | var tp = assembly.GetType(typeName); 48 | var info = GetAllMethods(tp).Where(f => f.IsStatic).Where(f => f.Name == methodName && f.GetParameters().Length == prm.Length).Single(); 49 | object rez = info.Invoke(null, prm); 50 | return rez; 51 | } 52 | public static object GetEnumValue(this Assembly assembly, string typeName, int value) { 53 | var tp = assembly.GetType(typeName); 54 | object rez = Enum.ToObject(tp, value); 55 | return rez; 56 | } 57 | 58 | private static IEnumerable GetAllFields(Type t) { 59 | if (t == null) 60 | return Enumerable.Empty(); 61 | 62 | BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; 63 | return t.GetFields(flags).Concat(GetAllFields(t.BaseType)); 64 | } 65 | private static IEnumerable GetAllProperties(Type t) { 66 | if (t == null) 67 | return Enumerable.Empty(); 68 | 69 | BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; 70 | return t.GetProperties(flags).Concat(GetAllProperties(t.BaseType)); 71 | } 72 | private static IEnumerable GetAllMethods(Type t) { 73 | if (t == null) 74 | return Enumerable.Empty(); 75 | 76 | BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; 77 | return t.GetMethods(flags).Concat(GetAllMethods(t.BaseType)); 78 | } 79 | #endif 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /FluentFTP.Examples/DereferenceLink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using FluentFTP; 4 | 5 | namespace Examples { 6 | static class DereferenceLink { 7 | /// 8 | /// Example illustrating how to dereference a symbolic link 9 | /// in a file listing. You can also pass the FtpListOption.DerefLinks 10 | /// flag to GetListing() to have automatically done in which 11 | /// case the FtpListItem.LinkObject property will contain the 12 | /// FtpListItem representing the object the link points at. The 13 | /// LinkObject property will be null if there was a problem resolving 14 | /// the target. 15 | /// 16 | public static void DereferenceLinkExample() { 17 | using (FtpClient client = new FtpClient()) { 18 | client.Credentials = new NetworkCredential("user", "pass"); 19 | client.Host = "somehost"; 20 | 21 | // This propety controls the depth of recursion that 22 | // can be done before giving up on resolving the link. 23 | // You can set the value to -1 for infinite depth 24 | // however you are strongly discourage from doing so. 25 | // The default value is 20, the following line is 26 | // only to illustrate the existance of the property. 27 | // It's also possible to override this value as one 28 | // of the overloaded arguments to the DereferenceLink() method. 29 | client.MaximumDereferenceCount = 20; 30 | 31 | // Notice the FtpListOption.ForceList flag being passed. This is because 32 | // symbolic links are only supported in UNIX style listings. My personal 33 | // experience has been that in practice MLSD listings don't specify an object 34 | // as a link, but rather list the link as a regular file or directory 35 | // accordingly. This may not always be the case however that's what I've 36 | // observed over the life of this project so if you run across the contrary 37 | // please report it. The specification for MLSD does include links so it's 38 | // possible some FTP server implementations do include links in the MLSD listing. 39 | foreach (FtpListItem item in client.GetListing(null, FtpListOption.ForceList | FtpListOption.Modify)) { 40 | Console.WriteLine(item); 41 | 42 | // If you call DerefenceLink() on a FtpListItem.Type other 43 | // than Link a FtpException will be thrown. If you call the 44 | // method and the LinkTarget is null a FtpException will also 45 | // be thrown. 46 | if (item.Type == FtpFileSystemObjectType.Link && item.LinkTarget != null) { 47 | item.LinkObject = client.DereferenceLink(item); 48 | 49 | // The return value of DerefenceLink() will be null 50 | // if there was a problem. 51 | if (item.LinkObject != null) { 52 | Console.WriteLine(item.LinkObject); 53 | } 54 | } 55 | } 56 | 57 | // This example is similar except it uses the FtpListOption.DerefLinks 58 | // flag to have symbolic links automatically resolved. You must manually 59 | // specify this flag because of the added overhead with regards to resolving 60 | // the target of a link. 61 | foreach (FtpListItem item in client.GetListing(null, 62 | FtpListOption.ForceList | FtpListOption.Modify | FtpListOption.DerefLinks)) { 63 | 64 | Console.WriteLine(item); 65 | 66 | if (item.Type == FtpFileSystemObjectType.Link && item.LinkObject != null) { 67 | Console.WriteLine(item.LinkObject); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /FluentFTP/Proxy/FtpClientHttp11Proxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace FluentFTP.Proxy { 6 | /// A FTP client with a HTTP 1.1 proxy implementation. 7 | public class FtpClientHttp11Proxy : FtpClientProxy { 8 | /// A FTP client with a HTTP 1.1 proxy implementation 9 | /// Proxy information 10 | public FtpClientHttp11Proxy(ProxyInfo proxy) 11 | : base(proxy) { 12 | ConnectionType = "HTTP 1.1 Proxy"; 13 | } 14 | 15 | /// Redefine the first dialog: HTTP Frame for the HTTP 1.1 Proxy 16 | protected override void Handshake() { 17 | var proxyConnectionReply = GetReply(); 18 | if (!proxyConnectionReply.Success) 19 | throw new FtpException("Can't connect " + Host + " via proxy " + Proxy.Host + ".\nMessage : " + 20 | proxyConnectionReply.ErrorMessage); 21 | } 22 | 23 | /// 24 | /// Creates a new instance of this class. Useful in FTP proxy classes. 25 | /// 26 | protected override FtpClient Create() { 27 | return new FtpClientHttp11Proxy(Proxy); 28 | } 29 | 30 | /// 31 | /// Connects to the server using an existing 32 | /// 33 | /// The existing socket stream 34 | protected override void Connect(FtpSocketStream stream) { 35 | Connect(stream, Host, Port, FtpIpVersion.ANY); 36 | } 37 | 38 | /// 39 | /// Connects to the server using an existing 40 | /// 41 | /// The existing socket stream 42 | /// Host name 43 | /// Port number 44 | /// IP version to use 45 | protected override void Connect(FtpSocketStream stream, string host, int port, FtpIpVersion ipVersions) { 46 | base.Connect(stream); 47 | 48 | var writer = new StreamWriter(stream); 49 | writer.WriteLine("CONNECT {0}:{1} HTTP/1.1", host, port); 50 | writer.WriteLine("Host: {0}:{1}", host, port); 51 | if (Proxy.Credentials != null) { 52 | var credentialsHash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Proxy.Credentials.UserName + ":"+ Proxy.Credentials.Password)); 53 | writer.WriteLine("Proxy-Authorization: Basic "+ credentialsHash); 54 | } 55 | writer.WriteLine("User-Agent: custom-ftp-client"); 56 | writer.WriteLine(); 57 | writer.Flush(); 58 | 59 | ProxyHandshake(stream); 60 | } 61 | 62 | private void ProxyHandshake(FtpSocketStream stream) { 63 | var proxyConnectionReply = GetProxyReply(stream); 64 | if (!proxyConnectionReply.Success) 65 | throw new FtpException("Can't connect " + Host + " via proxy " + Proxy.Host + ".\nMessage : " + proxyConnectionReply.ErrorMessage); 66 | } 67 | 68 | private FtpReply GetProxyReply( FtpSocketStream stream ) { 69 | 70 | FtpReply reply = new FtpReply(); 71 | string buf; 72 | 73 | #if !CORE14 74 | lock ( Lock ) { 75 | #endif 76 | if( !IsConnected ) 77 | throw new InvalidOperationException( "No connection to the server has been established." ); 78 | 79 | stream.ReadTimeout = ReadTimeout; 80 | while( ( buf = stream.ReadLine( Encoding ) ) != null ) { 81 | Match m; 82 | 83 | FtpTrace.WriteLine(FtpTraceLevel.Info, buf); 84 | 85 | if( ( m = Regex.Match( buf, @"^HTTP/.*\s(?[0-9]{3}) (?.*)$" ) ).Success ) { 86 | reply.Code = m.Groups[ "code" ].Value; 87 | reply.Message = m.Groups[ "message" ].Value; 88 | break; 89 | } 90 | 91 | reply.InfoMessages += ( buf+"\n" ); 92 | } 93 | 94 | // fixes #84 (missing bytes when downloading/uploading files through proxy) 95 | while( ( buf = stream.ReadLine( Encoding ) ) != null ) { 96 | 97 | FtpTrace.WriteLine(FtpTraceLevel.Info, buf); 98 | 99 | if (FtpExtensions.IsNullOrWhiteSpace(buf)) { 100 | break; 101 | } 102 | 103 | reply.InfoMessages += ( buf+"\n" ); 104 | } 105 | 106 | #if !CORE14 107 | } 108 | #endif 109 | 110 | return reply; 111 | } 112 | 113 | } 114 | } -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | #if !CORE 3 | using System.Runtime.Serialization; 4 | #endif 5 | 6 | namespace FluentFTP { 7 | /// 8 | /// FTP related error 9 | /// 10 | #if !CORE 11 | [Serializable] 12 | #endif 13 | public class FtpException : Exception { 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The error message 19 | public FtpException(string message) : base(message) { } 20 | /// 21 | /// Initializes a new instance of the class with an inner exception. 22 | /// 23 | /// The error message that explains the reason for the exception. 24 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. 25 | public FtpException(string message, Exception innerException) : base(message, innerException) { } 26 | 27 | #if !CORE 28 | /// 29 | /// Must be implemented so every Serializer can Deserialize the Exception 30 | /// 31 | protected FtpException(SerializationInfo info, StreamingContext context) : base(info, context) { } 32 | #endif 33 | } 34 | 35 | /// 36 | /// Exception triggered on command failures 37 | /// 38 | #if !CORE 39 | [Serializable] 40 | #endif 41 | public class FtpCommandException : FtpException { 42 | string _code = null; 43 | /// 44 | /// Gets the completion code associated with the response 45 | /// 46 | public string CompletionCode { 47 | get { return _code; } 48 | private set { _code = value; } 49 | } 50 | 51 | /// 52 | /// The type of response received from the last command executed 53 | /// 54 | public FtpResponseType ResponseType { 55 | get { 56 | if (_code != null) { 57 | // we only care about error types, if an exception 58 | // is being thrown for a successful response there 59 | // is a problem. 60 | switch (_code[0]) { 61 | case '4': 62 | return FtpResponseType.TransientNegativeCompletion; 63 | case '5': 64 | return FtpResponseType.PermanentNegativeCompletion; 65 | } 66 | } 67 | 68 | return FtpResponseType.None; 69 | } 70 | } 71 | 72 | /// 73 | /// Initializes a new instance of a FtpResponseException 74 | /// 75 | /// Status code 76 | /// Associated message 77 | public FtpCommandException(string code, string message) 78 | : base(message) { 79 | CompletionCode = code; 80 | } 81 | 82 | /// 83 | /// Initializes a new instance of a FtpResponseException 84 | /// 85 | /// The FtpReply to build the exception from 86 | public FtpCommandException(FtpReply reply) 87 | : this(reply.Code, reply.ErrorMessage) { 88 | } 89 | 90 | #if !CORE 91 | /// 92 | /// Must be implemented so every Serializer can Deserialize the Exception 93 | /// 94 | protected FtpCommandException(SerializationInfo info, StreamingContext context) : base(info, context) { } 95 | #endif 96 | } 97 | 98 | /// 99 | /// Exception is thrown when encryption could not be negotiated by the server 100 | /// 101 | #if !CORE 102 | [Serializable] 103 | #endif 104 | public class FtpSecurityNotAvailableException : FtpException { 105 | /// 106 | /// Default constructor 107 | /// 108 | public FtpSecurityNotAvailableException() 109 | : base("Security is not available on the server.") { 110 | } 111 | 112 | /// 113 | /// Custom error message 114 | /// 115 | /// Error message 116 | public FtpSecurityNotAvailableException(string message) 117 | : base(message) { 118 | } 119 | 120 | #if !CORE 121 | /// 122 | /// Must be implemented so every Serializer can Deserialize the Exception 123 | /// 124 | protected FtpSecurityNotAvailableException(SerializationInfo info, StreamingContext context) : base(info, context) { } 125 | #endif 126 | } 127 | } -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography; 4 | 5 | namespace FluentFTP { 6 | /// 7 | /// Represents a computed hash of an object 8 | /// on the FTP server. See the following link 9 | /// for more information: 10 | /// http://tools.ietf.org/html/draft-bryan-ftpext-hash-02 11 | /// 12 | public class FtpHash { 13 | FtpHashAlgorithm m_algorithm = FtpHashAlgorithm.NONE; 14 | /// 15 | /// Gets the algorithm that was used to compute the hash 16 | /// 17 | public FtpHashAlgorithm Algorithm { 18 | get { return m_algorithm; } 19 | internal set { m_algorithm = value; } 20 | } 21 | 22 | string m_value = null; 23 | /// 24 | /// Gets the computed hash returned by the server 25 | /// 26 | public string Value { 27 | get { return m_value; } 28 | internal set { m_value = value; } 29 | } 30 | 31 | /// 32 | /// Gets a value indicating if this object represents a 33 | /// valid hash response from the server. 34 | /// 35 | public bool IsValid { 36 | get { return m_algorithm != FtpHashAlgorithm.NONE && !string.IsNullOrEmpty(m_value); } 37 | } 38 | 39 | /// 40 | /// Computes the hash for the specified file and compares 41 | /// it to the value in this object. CRC hashes are not supported 42 | /// because there is no built-in support in the .net framework and 43 | /// a CRC implementation exceeds the scope of this project. If you 44 | /// attempt to call this on a CRC hash a will 45 | /// be thrown. 46 | /// 47 | /// The file to compute the hash for 48 | /// True if the computed hash matches what's stored in this object. 49 | /// Thrown if called on a CRC Hash 50 | public bool Verify(string file) { 51 | using (FileStream istream = new FileStream(file, FileMode.Open, FileAccess.Read)) { 52 | return Verify(istream); 53 | } 54 | } 55 | 56 | /// 57 | /// Computes the hash for the specified stream and compares 58 | /// it to the value in this object. CRC hashes are not supported 59 | /// because there is no built-in support in the .net framework and 60 | /// a CRC implementation exceeds the scope of this project. If you 61 | /// attempt to call this on a CRC hash a will 62 | /// be thrown. 63 | /// 64 | /// The stream to compute the hash for 65 | /// True if the computed hash matches what's stored in this object. 66 | /// Thrown if called on a CRC Hash 67 | public bool Verify(Stream istream) { 68 | if (IsValid) { 69 | HashAlgorithm hashAlg = null; 70 | 71 | switch (m_algorithm) { 72 | case FtpHashAlgorithm.SHA1: 73 | #if CORE 74 | hashAlg = SHA1.Create(); 75 | #else 76 | hashAlg = new SHA1CryptoServiceProvider(); 77 | #endif 78 | break; 79 | #if !NET20 80 | case FtpHashAlgorithm.SHA256: 81 | #if CORE 82 | hashAlg = SHA256.Create(); 83 | #else 84 | hashAlg = new SHA256CryptoServiceProvider(); 85 | #endif 86 | break; 87 | case FtpHashAlgorithm.SHA512: 88 | #if CORE 89 | hashAlg = SHA512.Create(); 90 | #else 91 | hashAlg = new SHA512CryptoServiceProvider(); 92 | #endif 93 | break; 94 | #endif 95 | case FtpHashAlgorithm.MD5: 96 | #if CORE 97 | hashAlg = MD5.Create(); 98 | #else 99 | hashAlg = new MD5CryptoServiceProvider(); 100 | #endif 101 | break; 102 | case FtpHashAlgorithm.CRC: 103 | throw new NotImplementedException("There is no built in support for computing CRC hashes."); 104 | default: 105 | throw new NotImplementedException("Unknown hash algorithm: " + m_algorithm.ToString()); 106 | } 107 | 108 | try { 109 | byte[] data = null; 110 | string hash = ""; 111 | 112 | data = hashAlg.ComputeHash(istream); 113 | if (data != null) { 114 | foreach (byte b in data) { 115 | hash += b.ToString("x2"); 116 | } 117 | 118 | return (hash.ToUpper() == m_value.ToUpper()); 119 | } 120 | } finally { 121 | #if !NET20 && !NET35 // .NET 2.0 doesn't provide access to Dispose() for HashAlgorithm 122 | if (hashAlg != null) 123 | hashAlg.Dispose(); 124 | #endif 125 | } 126 | } 127 | 128 | return false; 129 | } 130 | 131 | /// 132 | /// Creates an empty instance. 133 | /// 134 | internal FtpHash() { 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /FluentFTP.Examples/CustomParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using FluentFTP; 4 | using System.Globalization; 5 | 6 | namespace Examples { 7 | /// 8 | /// This is an example a FTP file listing parser. This code in the example 9 | /// is currently used to parse UNIX style long listings and serves as an 10 | /// example for adding your own parser. 11 | /// 12 | class CustomParser { 13 | /// 14 | /// Adds a custom file listing parser 15 | /// 16 | public static void AddCustomParser() { 17 | FtpListParser.AddParser(new FtpListParser.Parser(ParseUnixList)); 18 | } 19 | 20 | /// 21 | /// Parses LIST format listings 22 | /// 23 | /// A line from the listing 24 | /// Server capabilities 25 | /// FtpListItem if the item is able to be parsed 26 | static FtpListItem ParseUnixList(string buf, FtpCapability capabilities) { 27 | FtpListItem item = new FtpListItem(); 28 | Match m = null; 29 | string regex = 30 | @"(?[\w-]{10})\s+" + 31 | @"(?\d+)\s+" + 32 | @"(?[\w\d]+)\s+" + 33 | @"(?[\w\d]+)\s+" + 34 | @"(?\d+)\s+" + 35 | @"(?\w+\s+\d+\s+\d+:\d+|\w+\s+\d+\s+\d+)\s+" + 36 | @"(?.*)$"; 37 | 38 | if (!(m = Regex.Match(buf, regex, RegexOptions.IgnoreCase)).Success) 39 | return null; 40 | 41 | if (m.Groups["permissions"].Value.StartsWith("d")) 42 | item.Type = FtpFileSystemObjectType.Directory; 43 | else if (m.Groups["permissions"].Value.StartsWith("-")) 44 | item.Type = FtpFileSystemObjectType.File; 45 | else 46 | return null; 47 | 48 | // if we can't determine a file name then 49 | // we are not considering this a successful parsing operation. 50 | if (m.Groups["name"].Value.Length < 1) 51 | return null; 52 | item.Name = m.Groups["name"].Value; 53 | 54 | if (item.Type == FtpFileSystemObjectType.Directory && (item.Name == "." || item.Name == "..")) 55 | return null; 56 | 57 | //// 58 | // Ignore the Modify times sent in LIST format for files 59 | // when the server has support for the MDTM command 60 | // because they will never be as accurate as what can be had 61 | // by using the MDTM command. MDTM does not work on directories 62 | // so if a modify time was parsed from the listing we will try 63 | // to convert it to a DateTime object and use it for directories. 64 | //// 65 | if ((!capabilities.HasFlag(FtpCapability.MDTM) || item.Type == FtpFileSystemObjectType.Directory) && m.Groups["modify"].Value.Length > 0) 66 | item.Modified = m.Groups["modify"].Value.GetFtpDate(DateTimeStyles.AssumeUniversal); 67 | 68 | if (m.Groups["size"].Value.Length > 0) { 69 | long size; 70 | 71 | if (long.TryParse(m.Groups["size"].Value, out size)) 72 | item.Size = size; 73 | } 74 | 75 | if (m.Groups["permissions"].Value.Length > 0) { 76 | Match perms = Regex.Match(m.Groups["permissions"].Value, 77 | @"[\w-]{1}(?[\w-]{3})(?[\w-]{3})(?[\w-]{3})", 78 | RegexOptions.IgnoreCase); 79 | 80 | if (perms.Success) { 81 | if (perms.Groups["owner"].Value.Length == 3) { 82 | if (perms.Groups["owner"].Value[0] == 'r') 83 | item.OwnerPermissions |= FtpPermission.Read; 84 | if (perms.Groups["owner"].Value[1] == 'w') 85 | item.OwnerPermissions |= FtpPermission.Write; 86 | if (perms.Groups["owner"].Value[2] == 'x' || perms.Groups["owner"].Value[2] == 's') 87 | item.OwnerPermissions |= FtpPermission.Execute; 88 | if (perms.Groups["owner"].Value[2] == 's' || perms.Groups["owner"].Value[2] == 'S') 89 | item.SpecialPermissions |= FtpSpecialPermissions.SetUserID; 90 | } 91 | 92 | if (perms.Groups["group"].Value.Length == 3) { 93 | if (perms.Groups["group"].Value[0] == 'r') 94 | item.GroupPermissions |= FtpPermission.Read; 95 | if (perms.Groups["group"].Value[1] == 'w') 96 | item.GroupPermissions |= FtpPermission.Write; 97 | if (perms.Groups["group"].Value[2] == 'x' || perms.Groups["group"].Value[2] == 's') 98 | item.GroupPermissions |= FtpPermission.Execute; 99 | if (perms.Groups["group"].Value[2] == 's' || perms.Groups["group"].Value[2] == 'S') 100 | item.SpecialPermissions |= FtpSpecialPermissions.SetGroupID; 101 | } 102 | 103 | if (perms.Groups["others"].Value.Length == 3) { 104 | if (perms.Groups["others"].Value[0] == 'r') 105 | item.OthersPermissions |= FtpPermission.Read; 106 | if (perms.Groups["others"].Value[1] == 'w') 107 | item.OthersPermissions |= FtpPermission.Write; 108 | if (perms.Groups["others"].Value[2] == 'x' || perms.Groups["others"].Value[2] == 't') 109 | item.OthersPermissions |= FtpPermission.Execute; 110 | if (perms.Groups["others"].Value[2] == 't' || perms.Groups["others"].Value[2] == 'T') 111 | item.SpecialPermissions |= FtpSpecialPermissions.Sticky; 112 | } 113 | } 114 | } 115 | 116 | return item; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /FluentFTP/Stream/FtpDataStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Text.RegularExpressions; 4 | using System.Diagnostics; 5 | using System.Threading; 6 | 7 | #if ASYNC 8 | using System.Threading.Tasks; 9 | #endif 10 | 11 | namespace FluentFTP { 12 | 13 | /// 14 | /// Base class for data stream connections 15 | /// 16 | public class FtpDataStream : FtpSocketStream { 17 | FtpReply m_commandStatus; 18 | /// 19 | /// Gets the status of the command that was used to open 20 | /// this data channel 21 | /// 22 | public FtpReply CommandStatus { 23 | get { 24 | return m_commandStatus; 25 | } 26 | set { 27 | m_commandStatus = value; 28 | } 29 | } 30 | 31 | FtpClient m_control = null; 32 | /// 33 | /// Gets or sets the control connection for this data stream. Setting 34 | /// the control connection causes the object to be cloned and a new 35 | /// connection is made to the server to carry out the task. This ensures 36 | /// that multiple streams can be opened simultaneously. 37 | /// 38 | public FtpClient ControlConnection { 39 | get { 40 | return m_control; 41 | } 42 | set { 43 | m_control = value; 44 | } 45 | } 46 | 47 | long m_length = 0; 48 | /// 49 | /// Gets or sets the length of the stream. Only valid for file transfers 50 | /// and only valid on servers that support the Size command. 51 | /// 52 | public override long Length { 53 | get { 54 | return m_length; 55 | } 56 | } 57 | 58 | long m_position = 0; 59 | /// 60 | /// Gets or sets the position of the stream 61 | /// 62 | public override long Position { 63 | get { 64 | return m_position; 65 | } 66 | set { 67 | throw new InvalidOperationException("You cannot modify the position of a FtpDataStream. This property is updated as data is read or written to the stream."); 68 | } 69 | } 70 | 71 | /// 72 | /// Reads data off the stream 73 | /// 74 | /// The buffer to read into 75 | /// Where to start in the buffer 76 | /// Number of bytes to read 77 | /// The number of bytes read 78 | public override int Read(byte[] buffer, int offset, int count) { 79 | int read = base.Read(buffer, offset, count); 80 | m_position += read; 81 | return read; 82 | } 83 | 84 | #if ASYNC 85 | /// 86 | /// Reads data off the stream asynchronously 87 | /// 88 | /// The buffer to read into 89 | /// Where to start in the buffer 90 | /// Number of bytes to read 91 | /// The cancellation token for this task 92 | /// The number of bytes read 93 | public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) { 94 | int read = await base.ReadAsync(buffer, offset, count, token); 95 | m_position += read; 96 | return read; 97 | } 98 | #endif 99 | 100 | /// 101 | /// Writes data to the stream 102 | /// 103 | /// The buffer to write to the stream 104 | /// Where to start in the buffer 105 | /// The number of bytes to write to the buffer 106 | public override void Write(byte[] buffer, int offset, int count) { 107 | base.Write(buffer, offset, count); 108 | m_position += count; 109 | } 110 | 111 | #if ASYNC 112 | /// 113 | /// Writes data to the stream asynchronously 114 | /// 115 | /// The buffer to write to the stream 116 | /// Where to start in the buffer 117 | /// The number of bytes to write to the buffer 118 | /// The for this task 119 | public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token) { 120 | await base.WriteAsync(buffer, offset, count, token); 121 | m_position += count; 122 | } 123 | #endif 124 | 125 | /// 126 | /// Sets the length of this stream 127 | /// 128 | /// Value to apply to the Length property 129 | public override void SetLength(long value) { 130 | m_length = value; 131 | } 132 | 133 | /// 134 | /// Sets the position of the stream. Intended to be used 135 | /// internally by FtpControlConnection. 136 | /// 137 | /// The position 138 | public void SetPosition(long pos) { 139 | m_position = pos; 140 | } 141 | 142 | /// 143 | /// Closes the connection and reads the server's reply 144 | /// 145 | public new FtpReply Close() { 146 | base.Close(); 147 | 148 | try { 149 | if (ControlConnection != null) 150 | return ControlConnection.CloseDataStream(this); 151 | } finally { 152 | m_commandStatus = new FtpReply(); 153 | m_control = null; 154 | } 155 | 156 | return new FtpReply(); 157 | } 158 | 159 | /// 160 | /// Creates a new data stream object 161 | /// 162 | /// The control connection to be used for carrying out this operation 163 | public FtpDataStream(FtpClient conn) : base(conn.SslProtocols) { 164 | if (conn == null) 165 | throw new ArgumentException("The control connection cannot be null."); 166 | 167 | ControlConnection = conn; 168 | // always accept certificate no matter what because if code execution ever 169 | // gets here it means the certificate on the control connection object being 170 | // cloned was already accepted. 171 | ValidateCertificate += new FtpSocketStreamSslValidation(delegate(FtpSocketStream obj, FtpSslValidationEventArgs e) { 172 | e.Accept = true; 173 | }); 174 | 175 | m_position = 0; 176 | } 177 | 178 | /// 179 | /// Finalizer 180 | /// 181 | ~FtpDataStream() { 182 | try { 183 | Dispose(); 184 | } catch (Exception ex) { 185 | FtpTrace.WriteLine(FtpTraceLevel.Warn, "[Finalizer] Caught and discarded an exception while disposing the FtpDataStream: "+ ex.ToString()); 186 | } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /FluentFTP/Client/IFtpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Net; 6 | using System.Security.Authentication; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Text; 9 | 10 | namespace FluentFTP { 11 | 12 | /// 13 | /// Interface for the FtpClient class. For detailed documentation of the methods, please see the FtpClient class. 14 | /// 15 | public interface IFtpClient { 16 | 17 | void DeleteFile(string path); 18 | void DeleteDirectory(string path); 19 | void DeleteDirectory(string path, FtpListOption options); 20 | bool DirectoryExists(string path); 21 | bool FileExists(string path); 22 | void CreateDirectory(string path); 23 | void CreateDirectory(string path, bool force); 24 | void Rename(string path, string dest); 25 | bool MoveFile(string path, string dest, FtpExists existsMode = FtpExists.Overwrite); 26 | bool MoveDirectory(string path, string dest, FtpExists existsMode = FtpExists.Overwrite); 27 | void SetFilePermissions(string path, int permissions); 28 | void Chmod(string path, int permissions); 29 | void SetFilePermissions(string path, FtpPermission owner, FtpPermission group, FtpPermission other); 30 | void Chmod(string path, FtpPermission owner, FtpPermission group, FtpPermission other); 31 | FtpListItem GetFilePermissions(string path); 32 | int GetChmod(string path); 33 | FtpListItem DereferenceLink(FtpListItem item); 34 | FtpListItem DereferenceLink(FtpListItem item, int recMax); 35 | void SetWorkingDirectory(string path); 36 | string GetWorkingDirectory(); 37 | long GetFileSize(string path); 38 | DateTime GetModifiedTime(string path, FtpDate type = FtpDate.Original); 39 | void SetModifiedTime(string path, DateTime date, FtpDate type = FtpDate.Original); 40 | bool IsDisposed { get; } 41 | FtpIpVersion InternetProtocolVersions { get; set; } 42 | int SocketPollInterval { get; set; } 43 | bool StaleDataCheck { get; set; } 44 | bool IsConnected { get; } 45 | bool EnableThreadSafeDataConnections { get; set; } 46 | Encoding Encoding { get; set; } 47 | string Host { get; set; } 48 | int Port { get; set; } 49 | NetworkCredential Credentials { get; set; } 50 | int MaximumDereferenceCount { get; set; } 51 | X509CertificateCollection ClientCertificates { get; } 52 | Func AddressResolver { get; set; } 53 | IEnumerable ActivePorts { get; set; } 54 | FtpDataConnectionType DataConnectionType { get; set; } 55 | bool UngracefullDisconnection { get; set; } 56 | int ConnectTimeout { get; set; } 57 | int ReadTimeout { get; set; } 58 | int DataConnectionConnectTimeout { get; set; } 59 | int DataConnectionReadTimeout { get; set; } 60 | bool SocketKeepAlive { get; set; } 61 | FtpCapability Capabilities { get; } 62 | FtpHashAlgorithm HashAlgorithms { get; } 63 | FtpEncryptionMode EncryptionMode { get; set; } 64 | bool DataConnectionEncryption { get; set; } 65 | SslProtocols SslProtocols { get; set; } 66 | string SystemType { get; } 67 | string ConnectionType { get; } 68 | FtpParser ListingParser { get; set; } 69 | CultureInfo ListingCulture { get; set; } 70 | double TimeOffset { get; set; } 71 | bool RecursiveList { get; set; } 72 | bool BulkListing { get; set; } 73 | int BulkListingLength { get; set; } 74 | int TransferChunkSize { get; set; } 75 | int RetryAttempts { get; set; } 76 | uint UploadRateLimit { get; set; } 77 | uint DownloadRateLimit { get; set; } 78 | FtpDataType UploadDataType { get; set; } 79 | FtpDataType DownloadDataType { get; set; } 80 | event FtpSslValidation ValidateCertificate; 81 | void Dispose(); 82 | FtpReply Execute(string command); 83 | FtpReply GetReply(); 84 | void Connect(); 85 | void Disconnect(); 86 | bool HasFeature(FtpCapability cap); 87 | void DisableUTF8(); 88 | FtpListItem GetObjectInfo(string path, bool dateModified = false); 89 | FtpListItem[] GetListing(); 90 | FtpListItem[] GetListing(string path); 91 | FtpListItem[] GetListing(string path, FtpListOption options); 92 | string[] GetNameListing(); 93 | string[] GetNameListing(string path); 94 | Stream OpenRead(string path); 95 | Stream OpenRead(string path, FtpDataType type); 96 | Stream OpenRead(string path, FtpDataType type, bool checkIfFileExists); 97 | Stream OpenRead(string path, FtpDataType type, long restart); 98 | Stream OpenRead(string path, long restart); 99 | Stream OpenRead(string path, long restart, bool checkIfFileExists); 100 | Stream OpenRead(string path, FtpDataType type, long restart, bool checkIfFileExists); 101 | Stream OpenWrite(string path); 102 | Stream OpenWrite(string path, FtpDataType type); 103 | Stream OpenWrite(string path, FtpDataType type, bool checkIfFileExists); 104 | Stream OpenAppend(string path); 105 | Stream OpenAppend(string path, FtpDataType type); 106 | Stream OpenAppend(string path, FtpDataType type, bool checkIfFileExists); 107 | int UploadFiles(IEnumerable localPaths, string remoteDir, FtpExists existsMode = FtpExists.Overwrite, bool createRemoteDir = true, 108 | FtpVerify verifyOptions = FtpVerify.None, FtpError errorHandling = FtpError.None); 109 | int UploadFiles(IEnumerable localFiles, string remoteDir, FtpExists existsMode = FtpExists.Overwrite, bool createRemoteDir = true, 110 | FtpVerify verifyOptions = FtpVerify.None, FtpError errorHandling = FtpError.None); 111 | int DownloadFiles(string localDir, IEnumerable remotePaths, bool overwrite = true, FtpVerify verifyOptions = FtpVerify.None, 112 | FtpError errorHandling = FtpError.None); 113 | bool UploadFile(string localPath, string remotePath, FtpExists existsMode = FtpExists.Overwrite, bool createRemoteDir = false, 114 | FtpVerify verifyOptions = FtpVerify.None); 115 | bool Upload(Stream fileStream, string remotePath, FtpExists existsMode = FtpExists.Overwrite, bool createRemoteDir = false); 116 | bool Upload(byte[] fileData, string remotePath, FtpExists existsMode = FtpExists.Overwrite, bool createRemoteDir = false); 117 | bool DownloadFile(string localPath, string remotePath, bool overwrite = true, FtpVerify verifyOptions = FtpVerify.None); 118 | bool Download(Stream outStream, string remotePath); 119 | bool Download(out byte[] outBytes, string remotePath); 120 | FtpHashAlgorithm GetHashAlgorithm(); 121 | void SetHashAlgorithm(FtpHashAlgorithm type); 122 | FtpHash GetHash(string path); 123 | FtpHash GetChecksum(string path); 124 | string GetMD5(string path); 125 | string GetXCRC(string path); 126 | string GetXMD5(string path); 127 | string GetXSHA1(string path); 128 | string GetXSHA256(string path); 129 | string GetXSHA512(string path); 130 | 131 | } 132 | } -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | using System.Globalization; 6 | using System.Threading; 7 | 8 | namespace FluentFTP { 9 | /// 10 | /// Represents a file system object on the server 11 | /// 12 | /// 13 | public class FtpListItem { 14 | 15 | /// 16 | /// Blank constructor; Fill args manually. 17 | /// 18 | /// NOTE TO USER : You should not need to construct this class manually except in advanced cases. Typically constructed by GetListing(). 19 | /// 20 | public FtpListItem() { 21 | } 22 | 23 | /// 24 | /// Constructor with mandatory args filled. 25 | /// 26 | /// NOTE TO USER : You should not need to construct this class manually except in advanced cases. Typically constructed by GetListing(). 27 | /// 28 | public FtpListItem(string raw, string name, long size, bool isDir, ref DateTime lastModifiedTime) { 29 | m_input = raw; 30 | m_name = name; 31 | m_size = size; 32 | m_type = isDir ? FtpFileSystemObjectType.Directory : FtpFileSystemObjectType.File; 33 | m_modified = lastModifiedTime; 34 | } 35 | 36 | FtpFileSystemObjectType m_type = 0; 37 | /// 38 | /// Gets the type of file system object. 39 | /// 40 | public FtpFileSystemObjectType Type { 41 | get { 42 | return m_type; 43 | } 44 | set { 45 | m_type = value; 46 | } 47 | } 48 | 49 | string m_path = null; 50 | /// 51 | /// Gets the full path name to the object. 52 | /// 53 | public string FullName { 54 | get { 55 | return m_path; 56 | } 57 | set { 58 | m_path = value; 59 | } 60 | } 61 | 62 | string m_name = null; 63 | /// 64 | /// Gets the name of the object. 65 | /// 66 | public string Name { 67 | get { 68 | if (m_name == null && m_path != null) 69 | return m_path.GetFtpFileName(); 70 | return m_name; 71 | } 72 | set { 73 | m_name = value; 74 | } 75 | } 76 | 77 | string m_linkTarget = null; 78 | /// 79 | /// Gets the target a symbolic link points to. 80 | /// 81 | public string LinkTarget { 82 | get { 83 | return m_linkTarget; 84 | } 85 | set { 86 | m_linkTarget = value; 87 | } 88 | } 89 | 90 | int m_linkCount = 0; 91 | /// 92 | /// Gets the number of links pointing to this file. Only supplied by Unix servers. 93 | /// 94 | public int LinkCount { 95 | get { 96 | return m_linkCount; 97 | } 98 | set { 99 | m_linkCount = value; 100 | } 101 | } 102 | 103 | FtpListItem m_linkObject = null; 104 | /// 105 | /// Gets the object that the LinkTarget points to. This property is null unless you pass the 106 | /// flag in which case GetListing() will try to resolve 107 | /// the target itself. 108 | /// 109 | public FtpListItem LinkObject { 110 | get { 111 | return m_linkObject; 112 | } 113 | set { 114 | m_linkObject = value; 115 | } 116 | } 117 | 118 | DateTime m_modified = DateTime.MinValue; 119 | /// 120 | /// Gets the last write time of the object. 121 | /// 122 | public DateTime Modified { 123 | get { 124 | return m_modified; 125 | } 126 | set { 127 | m_modified = value; 128 | } 129 | } 130 | 131 | DateTime m_created = DateTime.MinValue; 132 | /// 133 | /// Gets the created date of the object. 134 | /// 135 | public DateTime Created { 136 | get { 137 | return m_created; 138 | } 139 | set { 140 | m_created = value; 141 | } 142 | } 143 | 144 | long m_size = -1; 145 | /// 146 | /// Gets the size of the object. 147 | /// 148 | public long Size { 149 | get { 150 | return m_size; 151 | } 152 | set { 153 | m_size = value; 154 | } 155 | } 156 | 157 | FtpSpecialPermissions m_specialPermissions = FtpSpecialPermissions.None; 158 | /// 159 | /// Gets special UNIX permissions such as Sticky, SUID and SGID. 160 | /// 161 | public FtpSpecialPermissions SpecialPermissions { 162 | get { 163 | return m_specialPermissions; 164 | } 165 | set { 166 | m_specialPermissions = value; 167 | } 168 | } 169 | 170 | FtpPermission m_ownerPermissions = FtpPermission.None; 171 | /// 172 | /// Gets the owner permissions. 173 | /// 174 | public FtpPermission OwnerPermissions { 175 | get { 176 | return m_ownerPermissions; 177 | } 178 | set { 179 | m_ownerPermissions = value; 180 | } 181 | } 182 | 183 | FtpPermission m_groupPermissions = FtpPermission.None; 184 | /// 185 | /// Gets the group permissions. 186 | /// 187 | public FtpPermission GroupPermissions { 188 | get { 189 | return m_groupPermissions; 190 | } 191 | set { 192 | m_groupPermissions = value; 193 | } 194 | } 195 | 196 | FtpPermission m_otherPermissions = FtpPermission.None; 197 | /// 198 | /// Gets the others permissions. 199 | /// 200 | public FtpPermission OthersPermissions { 201 | get { 202 | return m_otherPermissions; 203 | } 204 | set { 205 | m_otherPermissions = value; 206 | } 207 | } 208 | 209 | string m_rawPermissions = null; 210 | /// 211 | /// Gets the raw string received for the file permissions. 212 | /// Use this if the other properties are blank/invalid. 213 | /// 214 | public string RawPermissions { 215 | get { 216 | return m_rawPermissions; 217 | } 218 | set { 219 | m_rawPermissions = value; 220 | } 221 | } 222 | 223 | int m_chmod = 0; 224 | /// 225 | /// Gets the file permissions in the CHMOD format. 226 | /// 227 | public int Chmod { 228 | get { 229 | return m_chmod; 230 | } 231 | set { 232 | m_chmod = value; 233 | } 234 | } 235 | 236 | /// 237 | /// Gets the raw string received for the file's GROUP permissions. 238 | /// Use this if the other properties are blank/invalid. 239 | /// 240 | public string RawGroup = null; 241 | /// 242 | /// Gets the raw string received for the file's OWNER permissions. 243 | /// Use this if the other properties are blank/invalid. 244 | /// 245 | public string RawOwner = null; 246 | 247 | 248 | string m_input = null; 249 | /// 250 | /// Gets the input string that was parsed to generate the 251 | /// values in this object. 252 | /// 253 | public string Input { 254 | get { 255 | return m_input; 256 | } 257 | set { 258 | m_input = value; 259 | } 260 | } 261 | 262 | /// 263 | /// Returns a string representation of this object and its properties 264 | /// 265 | /// A string representing this object 266 | public override string ToString() { 267 | StringBuilder sb = new StringBuilder(); 268 | if (Type == FtpFileSystemObjectType.File) { 269 | sb.Append("FILE"); 270 | } else if (Type == FtpFileSystemObjectType.Directory) { 271 | sb.Append("DIR "); 272 | } else if (Type == FtpFileSystemObjectType.Link) { 273 | sb.Append("LINK"); 274 | } 275 | sb.Append(" "); 276 | sb.Append(Name); 277 | if (Type == FtpFileSystemObjectType.File) { 278 | sb.Append(" "); 279 | sb.Append("("); 280 | sb.Append(Size.FileSizeToString()); 281 | sb.Append(")"); 282 | } 283 | if (Created != DateTime.MinValue) { 284 | sb.Append(" "); 285 | sb.Append("Created : "); 286 | sb.Append(Created.ToString()); 287 | } 288 | if (Modified != DateTime.MinValue) { 289 | sb.Append(" "); 290 | sb.Append("Modified : "); 291 | sb.Append(Modified.ToString()); 292 | } 293 | return sb.ToString(); 294 | } 295 | 296 | } 297 | } -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpTrace.cs: -------------------------------------------------------------------------------- 1 | #define TRACE 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | 6 | namespace FluentFTP { 7 | /// 8 | /// Used for transaction logging and debug information. 9 | /// 10 | public static class FtpTrace { 11 | 12 | #if !CORE 13 | private static volatile TraceSource m_traceSource = new TraceSource("FluentFTP") { 14 | Switch = new SourceSwitch("sourceSwitch", "Verbose") { Level = SourceLevels.All } 15 | }; 16 | 17 | static bool m_flushOnWrite = true; 18 | 19 | 20 | /// 21 | /// Should the trace listeners be flushed immediately after writing to them? 22 | /// 23 | public static bool FlushOnWrite { 24 | get { return m_flushOnWrite; } 25 | set { m_flushOnWrite = value; } 26 | } 27 | 28 | static bool m_prefix = false; 29 | 30 | /// 31 | /// Should the log entries be written with a prefix of "FluentFTP"? 32 | /// Useful if you have a single TraceListener shared across multiple libraries. 33 | /// 34 | public static bool LogPrefix { 35 | get { return m_prefix; } 36 | set { m_prefix = value; } 37 | } 38 | 39 | 40 | /// 41 | /// Add a TraceListner to the collection. You can use one of the predefined 42 | /// TraceListeners in the System.Diagnostics namespace, such as ConsoleTraceListener 43 | /// for logging to the console, or you can write your own deriving from 44 | /// System.Diagnostics.TraceListener. 45 | /// 46 | /// The TraceListener to add to the collection 47 | public static void AddListener(TraceListener listener) { 48 | lock (m_traceSource) { 49 | m_traceSource.Listeners.Add(listener); 50 | } 51 | } 52 | 53 | /// 54 | /// Remove the specified TraceListener from the collection 55 | /// 56 | /// The TraceListener to remove from the collection. 57 | public static void RemoveListener(TraceListener listener) { 58 | lock (m_traceSource) { 59 | m_traceSource.Listeners.Remove(listener); 60 | } 61 | } 62 | 63 | #endif 64 | 65 | #if CORE 66 | 67 | static bool m_LogToConsole = false; 68 | 69 | /// 70 | /// Should FTP communication be be logged to console? 71 | /// 72 | public static bool LogToConsole { 73 | get { return m_LogToConsole; } 74 | set { m_LogToConsole = value; } 75 | } 76 | 77 | static string m_LogToFile = null; 78 | 79 | /// 80 | /// Set this to a file path to append all FTP communication to it. 81 | /// 82 | public static string LogToFile { 83 | get { return m_LogToFile; } 84 | set { m_LogToFile = value; } 85 | } 86 | 87 | #endif 88 | static bool m_functions = true; 89 | 90 | /// 91 | /// Should the function calls be logged in Verbose mode? 92 | /// 93 | public static bool LogFunctions { 94 | get { return m_functions; } 95 | set { m_functions = value; } 96 | } 97 | 98 | static bool m_IP = true; 99 | 100 | /// 101 | /// Should the FTP server IP addresses be included in the logs? 102 | /// 103 | public static bool LogIP { 104 | get { return m_IP; } 105 | set { m_IP = value; } 106 | } 107 | 108 | static bool m_username = true; 109 | 110 | /// 111 | /// Should the FTP usernames be included in the logs? 112 | /// 113 | public static bool LogUserName { 114 | get { return m_username; } 115 | set { m_username = value; } 116 | } 117 | 118 | static bool m_password = false; 119 | 120 | /// 121 | /// Should the FTP passwords be included in the logs? 122 | /// 123 | public static bool LogPassword { 124 | get { return m_password; } 125 | set { m_password = value; } 126 | } 127 | 128 | static bool m_tracing = true; 129 | 130 | /// 131 | /// Should we trace at all? 132 | /// 133 | public static bool EnableTracing 134 | { 135 | get { return m_tracing; } 136 | set { m_tracing = value; } 137 | } 138 | 139 | /// 140 | /// Write to the TraceListeners 141 | /// 142 | /// The message to write 143 | //[Obsolete("Use overloads with FtpTraceLevel")] 144 | public static void Write(string message) { 145 | Write(FtpTraceLevel.Verbose, message); 146 | } 147 | 148 | /// 149 | /// Write to the TraceListeners 150 | /// 151 | /// The message to write 152 | //[Obsolete("Use overloads with FtpTraceLevel")] 153 | public static void WriteLine(object message) { 154 | Write(FtpTraceLevel.Verbose, message.ToString()); 155 | } 156 | 157 | /// 158 | /// Write to the TraceListeners 159 | /// 160 | /// The type of tracing event 161 | /// The message to write 162 | public static void WriteLine(FtpTraceLevel eventType, object message) { 163 | Write(eventType, message.ToString()); 164 | } 165 | 166 | /// 167 | /// Write to the TraceListeners, adding an automatic prefix to the message based on the `eventType` 168 | /// 169 | /// The type of tracing event 170 | /// The message to write 171 | public static void WriteStatus(FtpTraceLevel eventType, object message) { 172 | Write(eventType, TraceLevelPrefix(eventType) + message.ToString()); 173 | } 174 | 175 | /// 176 | /// Write to the TraceListeners, for the purpose of logging a API function call 177 | /// 178 | /// The name of the API function 179 | /// The args passed to the function 180 | public static void WriteFunc(string function, object[] args = null) { 181 | if (m_functions) { 182 | Write(FtpTraceLevel.Verbose, ""); 183 | Write(FtpTraceLevel.Verbose, "# " + function + "(" + args.ItemsToString().Join(", ") + ")"); 184 | } 185 | } 186 | 187 | 188 | /// 189 | /// Write to the TraceListeners 190 | /// 191 | /// The type of tracing event 192 | /// A formattable string to write 193 | public static void Write(FtpTraceLevel eventType, string message) { 194 | if(!EnableTracing) 195 | return; 196 | #if CORE 197 | #if DEBUG 198 | Debug.WriteLine(message); 199 | #else 200 | if (m_LogToConsole) { 201 | Console.WriteLine(message); 202 | } 203 | if (m_LogToFile != null) { 204 | File.AppendAllText(m_LogToFile, message + "\n"); 205 | } 206 | #endif 207 | #elif !CORE 208 | 209 | if (m_prefix) { 210 | 211 | // if prefix is wanted then use TraceEvent() 212 | m_traceSource.TraceEvent(TraceLevelTranslation(eventType), 0, message); 213 | 214 | } else { 215 | 216 | // if prefix is NOT wanted then write manually 217 | EmitEvent(m_traceSource, TraceLevelTranslation(eventType), message); 218 | 219 | } 220 | if (m_flushOnWrite) { 221 | m_traceSource.Flush(); 222 | } 223 | #endif 224 | } 225 | 226 | private static string TraceLevelPrefix(FtpTraceLevel level) { 227 | switch (level) { 228 | case FtpTraceLevel.Verbose: 229 | return "Status: "; 230 | case FtpTraceLevel.Info: 231 | return "Status: "; 232 | case FtpTraceLevel.Warn: 233 | return "Warning: "; 234 | case FtpTraceLevel.Error: 235 | return "Error: "; 236 | } 237 | return "Status: "; 238 | } 239 | 240 | #if !CORE 241 | 242 | private static TraceEventType TraceLevelTranslation(FtpTraceLevel level) { 243 | switch (level) { 244 | case FtpTraceLevel.Verbose: 245 | return TraceEventType.Verbose; 246 | case FtpTraceLevel.Info: 247 | return TraceEventType.Information; 248 | case FtpTraceLevel.Warn: 249 | return TraceEventType.Warning; 250 | case FtpTraceLevel.Error: 251 | return TraceEventType.Error; 252 | default: 253 | return TraceEventType.Verbose; 254 | } 255 | } 256 | 257 | static object traceSync = new object(); 258 | private static void EmitEvent(TraceSource traceSource, TraceEventType eventType, string message) { 259 | try { 260 | lock (traceSync) { 261 | if (traceSource.Switch.ShouldTrace(eventType)) { 262 | foreach (TraceListener listener in traceSource.Listeners) { 263 | try { 264 | listener.WriteLine(message); 265 | listener.Flush(); 266 | } catch { } 267 | } 268 | } 269 | } 270 | } catch { 271 | } 272 | } 273 | #endif 274 | } 275 | } -------------------------------------------------------------------------------- /FluentFTP/Stream/FtpSslStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | #if !CORE 5 | using System.Linq; 6 | using System.Net.Security; 7 | using System.Runtime.ConstrainedExecution; 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | #endif 11 | 12 | namespace FluentFTP { 13 | 14 | #if !CORE 15 | /// 16 | /// .NET SslStream doesn't close TLS connection properly. 17 | /// It does not send the close_notify alert before closing the connection. 18 | /// FtpSslStream uses unsafe code to do that. 19 | /// This is required when we want to downgrade the connection to plaintext using CCC command. 20 | /// Thanks to Neco @ https://stackoverflow.com/questions/237807/net-sslstream-doesnt-close-tls-connection-properly/22626756#22626756 21 | /// 22 | internal class FtpSslStream : SslStream { 23 | 24 | private bool sentCloseNotify = false; 25 | 26 | public FtpSslStream(Stream innerStream) 27 | : base(innerStream) { 28 | } 29 | public FtpSslStream(Stream innerStream, bool leaveInnerStreamOpen) 30 | : base(innerStream, leaveInnerStreamOpen) { 31 | } 32 | public FtpSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback) 33 | : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) { 34 | } 35 | public FtpSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback) 36 | : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback) { 37 | } 38 | #if !NET20 && !NET35 39 | public FtpSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy) 40 | : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback, encryptionPolicy) { 41 | } 42 | #endif 43 | public override void Close() { 44 | try { 45 | if (!sentCloseNotify) { 46 | SslDirectCall.CloseNotify(this); 47 | sentCloseNotify = true; 48 | } 49 | } finally { 50 | base.Close(); 51 | } 52 | } 53 | } 54 | 55 | internal unsafe static class SslDirectCall { 56 | /// 57 | /// Send an SSL close_notify alert. 58 | /// 59 | /// 60 | public static void CloseNotify(SslStream sslStream) { 61 | if (sslStream.IsAuthenticated && sslStream.CanWrite) { 62 | bool isServer = sslStream.IsServer; 63 | 64 | byte[] result; 65 | int resultSz; 66 | var asmbSystem = typeof(System.Net.Authorization).Assembly; 67 | 68 | int SCHANNEL_SHUTDOWN = 1; 69 | var workArray = BitConverter.GetBytes(SCHANNEL_SHUTDOWN); 70 | 71 | var sslstate = FtpReflection.GetField(sslStream, "_SslState"); 72 | var context = FtpReflection.GetProperty(sslstate, "Context"); 73 | 74 | var securityContext = FtpReflection.GetField(context, "m_SecurityContext"); 75 | var securityContextHandleOriginal = FtpReflection.GetField(securityContext, "_handle"); 76 | SslNativeApi.SSPIHandle securityContextHandle = default(SslNativeApi.SSPIHandle); 77 | securityContextHandle.HandleHi = (IntPtr)FtpReflection.GetField(securityContextHandleOriginal, "HandleHi"); 78 | securityContextHandle.HandleLo = (IntPtr)FtpReflection.GetField(securityContextHandleOriginal, "HandleLo"); 79 | 80 | var credentialsHandle = FtpReflection.GetField(context, "m_CredentialsHandle"); 81 | var credentialsHandleHandleOriginal = FtpReflection.GetField(credentialsHandle, "_handle"); 82 | SslNativeApi.SSPIHandle credentialsHandleHandle = default(SslNativeApi.SSPIHandle); 83 | credentialsHandleHandle.HandleHi = (IntPtr)FtpReflection.GetField(credentialsHandleHandleOriginal, "HandleHi"); 84 | credentialsHandleHandle.HandleLo = (IntPtr)FtpReflection.GetField(credentialsHandleHandleOriginal, "HandleLo"); 85 | 86 | int bufferSize = 1; 87 | SslNativeApi.SecurityBufferDescriptor securityBufferDescriptor = new SslNativeApi.SecurityBufferDescriptor(bufferSize); 88 | SslNativeApi.SecurityBufferStruct[] unmanagedBuffer = new SslNativeApi.SecurityBufferStruct[bufferSize]; 89 | 90 | fixed (SslNativeApi.SecurityBufferStruct* ptr = unmanagedBuffer) 91 | fixed (void* workArrayPtr = workArray) { 92 | securityBufferDescriptor.UnmanagedPointer = (void*)ptr; 93 | 94 | unmanagedBuffer[0].token = (IntPtr)workArrayPtr; 95 | unmanagedBuffer[0].count = workArray.Length; 96 | unmanagedBuffer[0].type = SslNativeApi.BufferType.Token; 97 | 98 | SslNativeApi.SecurityStatus status; 99 | status = (SslNativeApi.SecurityStatus)SslNativeApi.ApplyControlToken(ref securityContextHandle, securityBufferDescriptor); 100 | if (status == SslNativeApi.SecurityStatus.OK) { 101 | unmanagedBuffer[0].token = IntPtr.Zero; 102 | unmanagedBuffer[0].count = 0; 103 | unmanagedBuffer[0].type = SslNativeApi.BufferType.Token; 104 | 105 | SslNativeApi.SSPIHandle contextHandleOut = default(SslNativeApi.SSPIHandle); 106 | SslNativeApi.ContextFlags outflags = SslNativeApi.ContextFlags.Zero; 107 | long ts = 0; 108 | 109 | var inflags = SslNativeApi.ContextFlags.SequenceDetect | 110 | SslNativeApi.ContextFlags.ReplayDetect | 111 | SslNativeApi.ContextFlags.Confidentiality | 112 | SslNativeApi.ContextFlags.AcceptExtendedError | 113 | SslNativeApi.ContextFlags.AllocateMemory | 114 | SslNativeApi.ContextFlags.InitStream; 115 | 116 | if (isServer) { 117 | status = (SslNativeApi.SecurityStatus)SslNativeApi.AcceptSecurityContext(ref credentialsHandleHandle, ref securityContextHandle, null, 118 | inflags, SslNativeApi.Endianness.Native, ref contextHandleOut, securityBufferDescriptor, ref outflags, out ts); 119 | } else { 120 | status = (SslNativeApi.SecurityStatus)SslNativeApi.InitializeSecurityContextW(ref credentialsHandleHandle, ref securityContextHandle, null, 121 | inflags, 0, SslNativeApi.Endianness.Native, null, 0, ref contextHandleOut, securityBufferDescriptor, ref outflags, out ts); 122 | } 123 | if (status == SslNativeApi.SecurityStatus.OK) { 124 | byte[] resultArr = new byte[unmanagedBuffer[0].count]; 125 | Marshal.Copy(unmanagedBuffer[0].token, resultArr, 0, resultArr.Length); 126 | Marshal.FreeCoTaskMem(unmanagedBuffer[0].token); 127 | result = resultArr; 128 | resultSz = resultArr.Length; 129 | } else { 130 | throw new InvalidOperationException(string.Format("AcceptSecurityContext/InitializeSecurityContextW returned [{0}] during CloseNotify.", status)); 131 | } 132 | } else { 133 | throw new InvalidOperationException(string.Format("ApplyControlToken returned [{0}] during CloseNotify.", status)); 134 | } 135 | } 136 | 137 | var innerStream = (Stream)FtpReflection.GetProperty(sslstate, "InnerStream"); 138 | innerStream.Write(result, 0, resultSz); 139 | } 140 | } 141 | } 142 | 143 | internal unsafe static class SslNativeApi { 144 | internal enum BufferType { 145 | Empty, 146 | Data, 147 | Token, 148 | Parameters, 149 | Missing, 150 | Extra, 151 | Trailer, 152 | Header, 153 | Padding = 9, 154 | Stream, 155 | ChannelBindings = 14, 156 | TargetHost = 16, 157 | ReadOnlyFlag = -2147483648, 158 | ReadOnlyWithChecksum = 268435456 159 | } 160 | 161 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 162 | internal struct SSPIHandle { 163 | public IntPtr HandleHi; 164 | public IntPtr HandleLo; 165 | public bool IsZero { 166 | get { 167 | return this.HandleHi == IntPtr.Zero && this.HandleLo == IntPtr.Zero; 168 | } 169 | } 170 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 171 | internal void SetToInvalid() { 172 | this.HandleHi = IntPtr.Zero; 173 | this.HandleLo = IntPtr.Zero; 174 | } 175 | public override string ToString() { 176 | return this.HandleHi.ToString("x") + ":" + this.HandleLo.ToString("x"); 177 | } 178 | } 179 | [StructLayout(LayoutKind.Sequential)] 180 | internal class SecurityBufferDescriptor { 181 | public readonly int Version; 182 | public readonly int Count; 183 | public unsafe void* UnmanagedPointer; 184 | public SecurityBufferDescriptor(int count) { 185 | this.Version = 0; 186 | this.Count = count; 187 | this.UnmanagedPointer = null; 188 | } 189 | } 190 | 191 | [StructLayout(LayoutKind.Sequential)] 192 | internal struct SecurityBufferStruct { 193 | public int count; 194 | public BufferType type; 195 | public IntPtr token; 196 | public static readonly int Size = sizeof(SecurityBufferStruct); 197 | } 198 | 199 | internal enum SecurityStatus { 200 | OK, 201 | ContinueNeeded = 590610, 202 | CompleteNeeded, 203 | CompAndContinue, 204 | ContextExpired = 590615, 205 | CredentialsNeeded = 590624, 206 | Renegotiate, 207 | OutOfMemory = -2146893056, 208 | InvalidHandle, 209 | Unsupported, 210 | TargetUnknown, 211 | InternalError, 212 | PackageNotFound, 213 | NotOwner, 214 | CannotInstall, 215 | InvalidToken, 216 | CannotPack, 217 | QopNotSupported, 218 | NoImpersonation, 219 | LogonDenied, 220 | UnknownCredentials, 221 | NoCredentials, 222 | MessageAltered, 223 | OutOfSequence, 224 | NoAuthenticatingAuthority, 225 | IncompleteMessage = -2146893032, 226 | IncompleteCredentials = -2146893024, 227 | BufferNotEnough, 228 | WrongPrincipal, 229 | TimeSkew = -2146893020, 230 | UntrustedRoot, 231 | IllegalMessage, 232 | CertUnknown, 233 | CertExpired, 234 | AlgorithmMismatch = -2146893007, 235 | SecurityQosFailed, 236 | SmartcardLogonRequired = -2146892994, 237 | UnsupportedPreauth = -2146892989, 238 | BadBinding = -2146892986 239 | } 240 | [Flags] 241 | internal enum ContextFlags { 242 | Zero = 0, 243 | Delegate = 1, 244 | MutualAuth = 2, 245 | ReplayDetect = 4, 246 | SequenceDetect = 8, 247 | Confidentiality = 16, 248 | UseSessionKey = 32, 249 | AllocateMemory = 256, 250 | Connection = 2048, 251 | InitExtendedError = 16384, 252 | AcceptExtendedError = 32768, 253 | InitStream = 32768, 254 | AcceptStream = 65536, 255 | InitIntegrity = 65536, 256 | AcceptIntegrity = 131072, 257 | InitManualCredValidation = 524288, 258 | InitUseSuppliedCreds = 128, 259 | InitIdentify = 131072, 260 | AcceptIdentify = 524288, 261 | ProxyBindings = 67108864, 262 | AllowMissingBindings = 268435456, 263 | UnverifiedTargetName = 536870912 264 | } 265 | internal enum Endianness { 266 | Network, 267 | Native = 16 268 | } 269 | 270 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 271 | [DllImport("secur32.dll", ExactSpelling = true, SetLastError = true)] 272 | internal static extern int ApplyControlToken(ref SSPIHandle contextHandle, [In] [Out] SecurityBufferDescriptor outputBuffer); 273 | 274 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 275 | [DllImport("secur32.dll", ExactSpelling = true, SetLastError = true)] 276 | internal unsafe static extern int AcceptSecurityContext(ref SSPIHandle credentialHandle, ref SSPIHandle contextHandle, [In] SecurityBufferDescriptor inputBuffer, [In] ContextFlags inFlags, [In] Endianness endianness, ref SSPIHandle outContextPtr, [In] [Out] SecurityBufferDescriptor outputBuffer, [In] [Out] ref ContextFlags attributes, out long timeStamp); 277 | 278 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 279 | [DllImport("secur32.dll", ExactSpelling = true, SetLastError = true)] 280 | internal unsafe static extern int InitializeSecurityContextW(ref SSPIHandle credentialHandle, ref SSPIHandle contextHandle, [In] byte* targetName, [In] ContextFlags inFlags, [In] int reservedI, [In] Endianness endianness, [In] SecurityBufferDescriptor inputBuffer, [In] int reservedII, ref SSPIHandle outContextPtr, [In] [Out] SecurityBufferDescriptor outputBuffer, [In] [Out] ref ContextFlags attributes, out long timeStamp); 281 | } 282 | 283 | #endif 284 | } 285 | -------------------------------------------------------------------------------- /FluentFTP/Utils/FtpExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | using System.Globalization; 6 | #if (CORE || NETFX) 7 | using System.Diagnostics; 8 | #endif 9 | #if NET45 10 | using System.Threading.Tasks; 11 | using System.Collections; 12 | #endif 13 | 14 | namespace FluentFTP { 15 | /// 16 | /// Extension methods related to FTP tasks 17 | /// 18 | public static class FtpExtensions { 19 | 20 | /// 21 | /// Converts the specified path into a valid FTP file system path 22 | /// 23 | /// The file system path 24 | /// A path formatted for FTP 25 | public static string GetFtpPath(this string path) { 26 | if (String.IsNullOrEmpty(path)) 27 | return "./"; 28 | 29 | path = path.Replace('\\', '/'); 30 | path = Regex.Replace(path, "[/]+", "/"); 31 | path = path.TrimEnd('/'); 32 | 33 | if (path.Length == 0) 34 | path = "/"; 35 | 36 | return path; 37 | } 38 | 39 | /// 40 | /// Creates a valid FTP path by appending the specified segments to this string 41 | /// 42 | /// This string 43 | /// The path segments to append 44 | /// A valid FTP path 45 | public static string GetFtpPath(this string path, params string[] segments) { 46 | if (String.IsNullOrEmpty(path)) 47 | path = "./"; 48 | 49 | foreach (string part in segments) { 50 | if (part != null) { 51 | if (path.Length > 0 && !path.EndsWith("/")) 52 | path += "/"; 53 | path += Regex.Replace(part.Replace('\\', '/'), "[/]+", "/").TrimEnd('/'); 54 | } 55 | } 56 | 57 | path = Regex.Replace(path.Replace('\\', '/'), "[/]+", "/").TrimEnd('/'); 58 | if (path.Length == 0) 59 | path = "/"; 60 | 61 | /*if (!path.StartsWith("/") || !path.StartsWith("./")) 62 | path = "./" + path;*/ 63 | 64 | return path; 65 | } 66 | 67 | /// 68 | /// Gets the parent directory path (formatted for a FTP server) 69 | /// 70 | /// The path 71 | /// The parent directory path 72 | public static string GetFtpDirectoryName(this string path) { 73 | string tpath = (path == null ? "" : path.GetFtpPath()); 74 | 75 | if (tpath.Length == 0 || tpath == "/") 76 | return "/"; 77 | 78 | int lastslash = tpath.LastIndexOf('/'); 79 | if (lastslash < 0) 80 | return "."; 81 | if (lastslash == 0) 82 | return "/"; 83 | 84 | return tpath.Substring(0, lastslash); 85 | } 86 | 87 | /*public static string GetFtpDirectoryName(this string path) { 88 | if (path == null || path.Length == 0 || path.GetFtpPath() == "/") 89 | return "/"; 90 | 91 | return System.IO.Path.GetDirectoryName(path).GetFtpPath(); 92 | }*/ 93 | 94 | /// 95 | /// Gets the file name and extension from the path 96 | /// 97 | /// The full path to the file 98 | /// The file name 99 | public static string GetFtpFileName(this string path) { 100 | string tpath = (path == null ? null : path); 101 | int lastslash = -1; 102 | 103 | if (tpath == null) 104 | return null; 105 | 106 | lastslash = tpath.LastIndexOf('/'); 107 | if (lastslash < 0) 108 | return tpath; 109 | 110 | lastslash += 1; 111 | if (lastslash >= tpath.Length) 112 | return tpath; 113 | 114 | return tpath.Substring(lastslash, tpath.Length - lastslash); 115 | } 116 | 117 | /*public static string GetFtpFileName(this string path) { 118 | return System.IO.Path.GetFileName(path).GetFtpPath(); 119 | }*/ 120 | 121 | private static string[] FtpDateFormats = { "yyyyMMddHHmmss", "yyyyMMddHHmmss'.'f", "yyyyMMddHHmmss'.'ff", "yyyyMMddHHmmss'.'fff", "MMM dd yyyy","MMM d yyyy","MMM dd HH:mm","MMM d HH:mm" }; 122 | 123 | /// 124 | /// Tries to convert the string FTP date representation into a object 125 | /// 126 | /// The date 127 | /// UTC/Local Time 128 | /// A object representing the date, or if there was a problem 129 | public static DateTime GetFtpDate(this string date, DateTimeStyles style) { 130 | DateTime parsed; 131 | 132 | if (DateTime.TryParseExact(date, FtpDateFormats, CultureInfo.InvariantCulture, style, out parsed)) { 133 | return parsed; 134 | } 135 | 136 | return DateTime.MinValue; 137 | } 138 | 139 | private static string[] sizePostfix = { "bytes", "KB", "MB", "GB", "TB" }; 140 | 141 | /// 142 | /// Converts a file size in bytes to a string representation (eg. 12345 becomes 12.3 KB) 143 | /// 144 | public static string FileSizeToString(this int bytes) { 145 | return ((long)bytes).FileSizeToString(); 146 | } 147 | /// 148 | /// Converts a file size in bytes to a string representation (eg. 12345 becomes 12.3 KB) 149 | /// 150 | public static string FileSizeToString(this uint bytes) { 151 | return ((long)bytes).FileSizeToString(); 152 | } 153 | /// 154 | /// Converts a file size in bytes to a string representation (eg. 12345 becomes 12.3 KB) 155 | /// 156 | public static string FileSizeToString(this ulong bytes) { 157 | return ((long)bytes).FileSizeToString(); 158 | } 159 | /// 160 | /// Converts a file size in bytes to a string representation (eg. 12345 becomes 12.3 KB) 161 | /// 162 | public static string FileSizeToString(this long bytes) { 163 | int order = 0; 164 | double len = bytes; 165 | while (len >= 1024 && order < sizePostfix.Length - 1) { 166 | order++; 167 | len = len / 1024; 168 | } 169 | return String.Format("{0:0.#} {1}", len, sizePostfix[order]); 170 | } 171 | 172 | #if NET45 173 | /// 174 | /// This creates a that represents a pair of begin and end methods 175 | /// that conform to the Asynchronous Programming Model pattern. This extends the maximum amount of arguments from 176 | /// to 4 from a 3. 177 | /// 178 | /// The type of the first argument passed to the delegate 179 | /// The type of the second argument passed to the delegate 180 | /// The type of the third argument passed to the delegate 181 | /// The type of the forth argument passed to the delegate 182 | /// The type of the result. 183 | /// The used 184 | /// The delegate that begins the asynchronous operation 185 | /// The delegate that ends the asynchronous operation 186 | /// The first argument passed to the delegate 187 | /// The second argument passed to the delegate 188 | /// The third argument passed to the delegate 189 | /// The forth argument passed to the delegate 190 | /// An object containing data to be used by the delegate 191 | /// The created that represents the asynchronous operation 192 | /// 193 | /// beginMethod is null 194 | /// or 195 | /// endMethod is null 196 | /// 197 | public static Task FromAsync(this TaskFactory factory, 198 | Func beginMethod, 199 | Func endMethod, 200 | TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, object state) { 201 | if (beginMethod == null) 202 | throw new ArgumentNullException("beginMethod"); 203 | 204 | if (endMethod == null) 205 | throw new ArgumentNullException("endMethod"); 206 | 207 | TaskCompletionSource tcs = new TaskCompletionSource(state, factory.CreationOptions); 208 | try { 209 | AsyncCallback callback = delegate(IAsyncResult asyncResult) { 210 | tcs.TrySetResult(endMethod(asyncResult)); 211 | }; 212 | 213 | beginMethod(arg1, arg2, arg3, arg4, callback, state); 214 | } 215 | catch { 216 | tcs.TrySetResult(default(TResult)); 217 | throw; 218 | } 219 | 220 | return tcs.Task; 221 | } 222 | #endif 223 | 224 | /// 225 | /// Validates that the FtpError flags set are not in an invalid combination. 226 | /// 227 | /// The error handling options set 228 | /// True if a valid combination, otherwise false 229 | public static bool IsValidCombination(this FtpError options) { 230 | return options != (FtpError.Stop | FtpError.Throw) && 231 | options != (FtpError.Throw | FtpError.Stop | FtpError.DeleteProcessed); 232 | } 233 | 234 | /// 235 | /// Checks if every character in the string is whitespace, or the string is null. 236 | /// 237 | public static bool IsNullOrWhiteSpace(string value) { 238 | if (value == null) return true; 239 | 240 | for (int i = 0; i < value.Length; i++) { 241 | if (!Char.IsWhiteSpace(value[i])) return false; 242 | } 243 | 244 | return true; 245 | } 246 | 247 | /// 248 | /// Checks if the string is null or 0 length. 249 | /// 250 | public static bool IsBlank(this string value) { 251 | return value == null || value.Length == 0; 252 | } 253 | 254 | #if NET45 255 | /// 256 | /// Checks if the array is null or 0 length. 257 | /// 258 | public static bool IsBlank(this IList value) { 259 | return value == null || value.Count == 0; 260 | } 261 | 262 | /// 263 | /// Checks if the array is null or 0 length. 264 | /// 265 | public static bool IsBlank(this IEnumerable value) { 266 | if (value == null){ 267 | return true; 268 | } 269 | if (value is IList){ 270 | return ((IList)value).Count == 0; 271 | } 272 | if (value is byte[]){ 273 | return ((byte[])value).Length == 0; 274 | } 275 | return false; 276 | } 277 | #endif 278 | 279 | /// 280 | /// Join the given strings by a delimiter. 281 | /// 282 | public static string Join(this string[] values, string delimiter) { 283 | return string.Join(delimiter, values); 284 | } 285 | 286 | /// 287 | /// Join the given strings by a delimiter. 288 | /// 289 | public static string Join(this List values, string delimiter) { 290 | #if NET20 || NET35 291 | return string.Join(delimiter, values.ToArray()); 292 | #else 293 | return string.Join(delimiter, values); 294 | #endif 295 | } 296 | 297 | /// 298 | /// Adds a prefix to the given strings, returns a new array. 299 | /// 300 | public static string[] AddPrefix(this string[] values, string prefix, bool trim = false) { 301 | List results = new List(); 302 | foreach (string v in values) { 303 | string txt = prefix + (trim ? v.Trim() : v); 304 | results.Add(txt); 305 | } 306 | return results.ToArray(); 307 | } 308 | /// 309 | /// Adds a prefix to the given strings, returns a new array. 310 | /// 311 | public static List AddPrefix(this List values, string prefix, bool trim = false) { 312 | List results = new List(); 313 | foreach (string v in values) { 314 | string txt = prefix + (trim ? v.Trim() : v); 315 | results.Add(txt); 316 | } 317 | return results; 318 | } 319 | 320 | /// 321 | /// Adds a prefix to the given strings, returns a new array. 322 | /// 323 | public static List ItemsToString(this object[] args) { 324 | List results = new List(); 325 | if (args == null) { 326 | return results; 327 | } 328 | foreach (object v in args) { 329 | string txt; 330 | if (v == null){ 331 | txt = "null"; 332 | } else if (v is string) { 333 | txt = ("\"" + v as string + "\""); 334 | } else { 335 | txt = v.ToString(); 336 | } 337 | results.Add(txt); 338 | } 339 | return results; 340 | } 341 | 342 | #if NET20 || NET35 343 | public static bool HasFlag(this FtpHashAlgorithm flags, FtpHashAlgorithm flag) { 344 | return (flags & flag) == flag; 345 | } 346 | public static bool HasFlag(this FtpCapability flags, FtpCapability flag) { 347 | return (flags & flag) == flag; 348 | } 349 | public static bool HasFlag(this FtpVerify flags, FtpVerify flag) { 350 | return (flags & flag) == flag; 351 | } 352 | public static bool HasFlag(this FtpError flags, FtpError flag) { 353 | return (flags & flag) == flag; 354 | } 355 | public static void Restart(this Stopwatch watch) { 356 | watch.Stop(); 357 | watch.Start(); 358 | } 359 | #endif 360 | 361 | 362 | } 363 | } -------------------------------------------------------------------------------- /FluentFTP/Helpers/FtpEnums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FluentFTP { 4 | 5 | /// 6 | /// Defines the type of encryption to use 7 | /// 8 | public enum FtpEncryptionMode { 9 | /// 10 | /// Plain text. 11 | /// 12 | None, 13 | /// 14 | /// FTPS encryption is used from the start of the connection, port 990. 15 | /// 16 | Implicit, 17 | /// 18 | /// Connection starts in plain text and FTPS encryption is enabled 19 | /// with the AUTH command immediately after the server greeting. 20 | /// 21 | Explicit 22 | } 23 | 24 | /// 25 | /// The type of response the server responded with 26 | /// 27 | public enum FtpResponseType : int { 28 | /// 29 | /// No response 30 | /// 31 | None = 0, 32 | /// 33 | /// Success 34 | /// 35 | PositivePreliminary = 1, 36 | /// 37 | /// Success 38 | /// 39 | PositiveCompletion = 2, 40 | /// 41 | /// Success 42 | /// 43 | PositiveIntermediate = 3, 44 | /// 45 | /// Temporary failure 46 | /// 47 | TransientNegativeCompletion = 4, 48 | /// 49 | /// Permanent failure 50 | /// 51 | PermanentNegativeCompletion = 5 52 | } 53 | 54 | /// 55 | /// Server features 56 | /// 57 | [Flags] 58 | public enum FtpCapability : int { 59 | /// 60 | /// This server said it doesn't support anything! 61 | /// 62 | NONE = 0, 63 | /// 64 | /// Supports the MLST command 65 | /// 66 | MLSD = 1, 67 | /// 68 | /// Supports the SIZE command 69 | /// 70 | SIZE = 2, 71 | /// 72 | /// Supports the MDTM command 73 | /// 74 | MDTM = 4, 75 | /// 76 | /// Supports download/upload stream resumes 77 | /// 78 | REST = 8, 79 | /// 80 | /// Supports UTF8 81 | /// 82 | UTF8 = 16, 83 | /// 84 | /// PRET Command used in distributed ftp server software DrFTPD 85 | /// 86 | PRET = 32, 87 | /// 88 | /// Server supports the MFMT command for setting the 89 | /// modified date of an object on the server 90 | /// 91 | MFMT = 64, 92 | /// 93 | /// Server supports the MFCT command for setting the 94 | /// created date of an object on the server 95 | /// 96 | MFCT = 128, 97 | /// 98 | /// Server supports the MFF command for setting certain facts 99 | /// about file system objects. If you need this command, it would 100 | /// probably be handy to query FEAT your self and have a look at 101 | /// the FtpReply.InfoMessages property to see which facts the server 102 | /// allows you to modify. 103 | /// 104 | MFF = 256, 105 | /// 106 | /// Server supports the STAT command 107 | /// 108 | STAT = 512, 109 | /// 110 | /// Support for the HASH command 111 | /// 112 | HASH = 1024, 113 | /// 114 | /// Support for the non-standard MD5 command 115 | /// 116 | MD5 = 2048, 117 | /// 118 | /// Support for the non-standard XMD5 command 119 | /// 120 | XMD5 = 4096, 121 | /// 122 | /// Support for the non-standard XCRC command 123 | /// 124 | XCRC = 8192, 125 | /// 126 | /// Support for the non-standard XSHA1 command 127 | /// 128 | XSHA1 = 16384, 129 | /// 130 | /// Support for the non-standard XSHA256 command 131 | /// 132 | XSHA256 = 32768, 133 | /// 134 | /// Support for the non-standard XSHA512 command 135 | /// 136 | XSHA512 = 65536 137 | } 138 | 139 | /// 140 | /// Different types of hashing algorithms for computing checksums. 141 | /// 142 | [Flags] 143 | public enum FtpHashAlgorithm : int { 144 | /// 145 | /// HASH command is not supported 146 | /// 147 | NONE = 0, 148 | /// 149 | /// SHA-1 150 | /// 151 | SHA1 = 1, 152 | /// 153 | /// SHA-256 154 | /// 155 | SHA256 = 2, 156 | /// 157 | /// SHA-512 158 | /// 159 | SHA512 = 4, 160 | /// 161 | /// MD5 162 | /// 163 | MD5 = 8, 164 | /// 165 | /// CRC 166 | /// 167 | CRC = 16 168 | } 169 | 170 | /// 171 | /// IP Versions to allow when connecting 172 | /// to a server. 173 | /// 174 | [Flags] 175 | public enum FtpIpVersion : int { 176 | /// 177 | /// Internet Protocol Version 4 178 | /// 179 | IPv4 = 1, 180 | /// 181 | /// Internet Protocol Version 6 182 | /// 183 | IPv6 = 2, 184 | /// 185 | /// Allow any supported version 186 | /// 187 | ANY = IPv4 | IPv6 188 | } 189 | 190 | /// 191 | /// Data connection type 192 | /// 193 | public enum FtpDataConnectionType { 194 | /// 195 | /// This type of data connection attempts to use the EPSV command 196 | /// and if the server does not support EPSV it falls back to the 197 | /// PASV command before giving up unless you are connected via IPv6 198 | /// in which case the PASV command is not supported. 199 | /// 200 | AutoPassive, 201 | /// 202 | /// Passive data connection. EPSV is a better 203 | /// option if it's supported. Passive connections 204 | /// connect to the IP address dictated by the server 205 | /// which may or may not be accessible by the client 206 | /// for example a server behind a NAT device may 207 | /// give an IP address on its local network that 208 | /// is inaccessible to the client. Please note that IPv6 209 | /// does not support this type data connection. If you 210 | /// ask for PASV and are connected via IPv6 EPSV will 211 | /// automatically be used in its place. 212 | /// 213 | PASV, 214 | /// 215 | /// Same as PASV except the host supplied by the server is ignored 216 | /// and the data connection is made to the same address that the control 217 | /// connection is connected to. This is useful in scenarios where the 218 | /// server supplies a private/non-routable network address in the 219 | /// PASV response. It's functionally identical to EPSV except some 220 | /// servers may not implement the EPSV command. Please note that IPv6 221 | /// does not support this type data connection. If you 222 | /// ask for PASV and are connected via IPv6 EPSV will 223 | /// automatically be used in its place. 224 | /// 225 | PASVEX, 226 | /// 227 | /// Extended passive data connection, recommended. Works 228 | /// the same as a PASV connection except the server 229 | /// does not dictate an IP address to connect to, instead 230 | /// the passive connection goes to the same address used 231 | /// in the control connection. This type of data connection 232 | /// supports IPv4 and IPv6. 233 | /// 234 | EPSV, 235 | /// 236 | /// This type of data connection attempts to use the EPRT command 237 | /// and if the server does not support EPRT it falls back to the 238 | /// PORT command before giving up unless you are connected via IPv6 239 | /// in which case the PORT command is not supported. 240 | /// 241 | AutoActive, 242 | /// 243 | /// Active data connection, not recommended unless 244 | /// you have a specific reason for using this type. 245 | /// Creates a listening socket on the client which 246 | /// requires firewall exceptions on the client system 247 | /// as well as client network when connecting to a 248 | /// server outside of the client's network. In addition 249 | /// the IP address of the interface used to connect to the 250 | /// server is the address the server is told to connect to 251 | /// which, if behind a NAT device, may be inaccessible to 252 | /// the server. This type of data connection is not supported 253 | /// by IPv6. If you specify PORT and are connected via IPv6 254 | /// EPRT will automatically be used instead. 255 | /// 256 | PORT, 257 | /// 258 | /// Extended active data connection, not recommended 259 | /// unless you have a specific reason for using this 260 | /// type. Creates a listening socket on the client 261 | /// which requires firewall exceptions on the client 262 | /// as well as client network when connecting to a 263 | /// server outside of the client's network. The server 264 | /// connects to the IP address it sees the client coming 265 | /// from. This type of data connection supports IPv4 and IPv6. 266 | /// 267 | EPRT 268 | } 269 | 270 | /// 271 | /// Type of data transfer to do 272 | /// 273 | public enum FtpDataType { 274 | /// 275 | /// ASCII transfer 276 | /// 277 | ASCII, 278 | /// 279 | /// Binary transfer 280 | /// 281 | Binary 282 | } 283 | 284 | /// 285 | /// Type of file system of object 286 | /// 287 | public enum FtpFileSystemObjectType { 288 | /// 289 | /// A file 290 | /// 291 | File, 292 | /// 293 | /// A directory 294 | /// 295 | Directory, 296 | /// 297 | /// A symbolic link 298 | /// 299 | Link 300 | } 301 | 302 | /// 303 | /// Types of file permissions 304 | /// 305 | [Flags] 306 | public enum FtpPermission : uint { 307 | /// 308 | /// No access 309 | /// 310 | None = 0, 311 | /// 312 | /// Executable 313 | /// 314 | Execute = 1, 315 | /// 316 | /// Writable 317 | /// 318 | Write = 2, 319 | /// 320 | /// Readable 321 | /// 322 | Read = 4 323 | } 324 | 325 | /// 326 | /// Types of special UNIX permissions 327 | /// 328 | [Flags] 329 | public enum FtpSpecialPermissions : int { 330 | /// 331 | /// No special permissions are set 332 | /// 333 | None = 0, 334 | /// 335 | /// Sticky bit is set 336 | /// 337 | Sticky = 1, 338 | /// 339 | /// SGID bit is set 340 | /// 341 | SetGroupID = 2, 342 | /// 343 | /// SUID bit is set 344 | /// 345 | SetUserID = 4 346 | } 347 | 348 | /// 349 | /// The type of response the server responded with 350 | /// 351 | public enum FtpParser : int { 352 | /// 353 | /// Use the legacy parser (for older projects that depend on the pre-2017 parser routines). 354 | /// 355 | Legacy = -1, 356 | /// 357 | /// Automatically detect the file listing parser to use based on the FTP server (SYST command). 358 | /// 359 | Auto = 0, 360 | /// 361 | /// Machine listing parser, works on any FTP server supporting the MLST/MLSD commands. 362 | /// 363 | Machine = 1, 364 | /// 365 | /// File listing parser for Windows/IIS. 366 | /// 367 | Windows = 2, 368 | /// 369 | /// File listing parser for Unix. 370 | /// 371 | Unix = 3, 372 | /// 373 | /// Alternate parser for Unix. Use this if the default one does not work. 374 | /// 375 | UnixAlt = 4, 376 | /// 377 | /// File listing parser for Vax/VMS/OpenVMS. 378 | /// 379 | VMS = 5, 380 | /// 381 | /// File listing parser for IBM OS400. 382 | /// 383 | IBM = 6, 384 | /// 385 | /// File listing parser for Tandem/Nonstop Guardian OS. 386 | /// 387 | NonStop = 7 388 | } 389 | 390 | /// 391 | /// Flags that can dictate how a file listing is performed 392 | /// 393 | [Flags] 394 | public enum FtpListOption { 395 | /// 396 | /// Tries machine listings (MDTM command) if supported, 397 | /// and if not then falls back to OS-specific listings (LIST command) 398 | /// 399 | Auto = 0, 400 | /// 401 | /// Load the modify date using MDTM when it could not 402 | /// be parsed from the server listing. This only pertains 403 | /// to servers that do not implement the MLSD command. 404 | /// 405 | Modify = 1, 406 | /// 407 | /// Load the file size using the SIZE command when it 408 | /// could not be parsed from the server listing. This 409 | /// only pertains to servers that do not support the 410 | /// MLSD command. 411 | /// 412 | Size = 2, 413 | /// 414 | /// Combines the Modify and Size flags 415 | /// 416 | SizeModify = Modify | Size, 417 | /// 418 | /// Show hidden/dot files. This only pertains to servers 419 | /// that do not support the MLSD command. This option 420 | /// makes use the non standard -a parameter to LIST to 421 | /// tell the server to show hidden files. Since it's a 422 | /// non-standard option it may not always work. MLSD listings 423 | /// have no such option and whether or not a hidden file is 424 | /// shown is at the discretion of the server. 425 | /// 426 | AllFiles = 4, 427 | /// 428 | /// Force the use of OS-specific listings (LIST command) even if 429 | /// machine listings (MLSD command) are supported by the server 430 | /// 431 | ForceList = 8, 432 | /// 433 | /// Use the NLST command instead of LIST for a reliable file listing 434 | /// 435 | NameList = 16, 436 | /// 437 | /// Force the use of the NLST command (the slowest mode) even if machine listings 438 | /// and OS-specific listings are supported by the server 439 | /// 440 | ForceNameList = ForceList | NameList, 441 | /// 442 | /// Try to dereference symbolic links, and stored the linked file/directory in FtpListItem.LinkObject 443 | /// 444 | DerefLinks = 32, 445 | /// 446 | /// Sets the ForceList flag and uses `LS' instead of `LIST' as the 447 | /// command for getting a directory listing. This option overrides 448 | /// ForceNameList and ignores the AllFiles flag. 449 | /// 450 | UseLS = 64 | ForceList, 451 | /// 452 | /// Gets files within subdirectories as well. Adds the -r option to the LIST command. 453 | /// Some servers may not support this feature. 454 | /// 455 | Recursive = 128, 456 | /// 457 | /// Do not retrieve path when no path is supplied to GetListing(), 458 | /// instead just execute LIST with no path argument. 459 | /// 460 | NoPath = 256, 461 | /// 462 | /// Include two extra items into the listing, for the current directory (".") 463 | /// and the parent directory (".."). Meaningless unless you want these two 464 | /// items for some reason. 465 | /// 466 | IncludeSelfAndParent = 512 467 | } 468 | 469 | /// 470 | /// Defines the behavior for uploading/downloading files that already exist 471 | /// 472 | public enum FtpExists { 473 | /// 474 | /// Do not check if the file exists. A bit faster than the other options. Only use this if you are SURE that the file does not exist on the server. 475 | /// Otherwise it can cause the UploadFile method to hang due to filesize mismatch. 476 | /// 477 | NoCheck, 478 | /// 479 | /// Skip the file if it exists, without any more checks. 480 | /// 481 | Skip, 482 | /// 483 | /// Overwrite the file if it exists. 484 | /// 485 | Overwrite, 486 | /// 487 | /// Append to the file if it exists, by checking the length and adding the missing data. 488 | /// 489 | Append 490 | } 491 | 492 | /// 493 | /// Defines the level of the tracing message. Depending on the framework version this is translated 494 | /// to an equivalent logging level in System.Diagnostices (if available) 495 | /// 496 | public enum FtpTraceLevel { 497 | /// 498 | /// Used for logging Debug or Verbose level messages 499 | /// 500 | Verbose, 501 | /// 502 | /// Used for logging Informational messages 503 | /// 504 | Info, 505 | /// 506 | /// Used for logging non-fatal or ignorable error messages 507 | /// 508 | Warn, 509 | /// 510 | /// Used for logging Error messages that may need investigation 511 | /// 512 | Error 513 | } 514 | 515 | /// 516 | /// Defines how multi-file processes should handle a processing error. 517 | /// 518 | /// & Cannot Be Combined 519 | [Flags] 520 | public enum FtpError { 521 | /// 522 | /// No action is taken upon errors. The method absorbs the error and continues. 523 | /// 524 | None = 0, 525 | /// 526 | /// If any files have completed successfully (or failed after a partial download/upload) then should be deleted. 527 | /// This will simulate an all-or-nothing transaction downloading or uploading multiple files. If this option is not 528 | /// combined with or then the method will 529 | /// continue to process all items whether if they are successful or not and then delete everything if a failure was 530 | /// encountered at any point. 531 | /// 532 | DeleteProcessed = 1, 533 | /// 534 | /// The method should stop processing any additional files and immediately return upon encountering an error. 535 | /// Cannot be combined with 536 | /// 537 | Stop = 2, 538 | /// 539 | /// The method should stop processing any additional files and immediately throw the current error. 540 | /// Cannot be combined with 541 | /// 542 | Throw = 4, 543 | 544 | } 545 | 546 | /// 547 | /// Defines if additional verification and actions upon failure that 548 | /// should be performed when uploading/downloading files using the high-level APIs. Ignored if the 549 | /// FTP server does not support any hashing algorithms. 550 | /// 551 | [Flags] 552 | public enum FtpVerify { 553 | /// 554 | /// No verification of the file is performed 555 | /// 556 | None = 0, 557 | /// 558 | /// The checksum of the file is verified, if supported by the server. 559 | /// If the checksum comparison fails then we retry the download/upload 560 | /// a specified amount of times before giving up. (See ) 561 | /// 562 | Retry = 1, 563 | /// 564 | /// The checksum of the file is verified, if supported by the server. 565 | /// If the checksum comparison fails then the failed file will be deleted. 566 | /// If combined with , then 567 | /// the deletion will occur if it fails upon the final retry. 568 | /// 569 | Delete = 2, 570 | /// 571 | /// The checksum of the file is verified, if supported by the server. 572 | /// If the checksum comparison fails then an exception will be thrown. 573 | /// If combined with , then the throw will 574 | /// occur upon the failure of the final retry, and/or if combined with 575 | /// the method will throw after the deletion is processed. 576 | /// 577 | Throw = 4, 578 | /// 579 | /// The checksum of the file is verified, if supported by the server. 580 | /// If the checksum comparison fails then the method returns false and no other action is taken. 581 | /// 582 | OnlyChecksum = 8, 583 | } 584 | 585 | /// 586 | /// Defines if additional verification and actions upon failure that 587 | /// should be performed when uploading/downloading files using the high-level APIs. Ignored if the 588 | /// FTP server does not support any hashing algorithms. 589 | /// 590 | public enum FtpDate { 591 | /// 592 | /// The date is whatever the server returns, with no conversion performed. 593 | /// 594 | Original = 0, 595 | /// 596 | #if !CORE 597 | /// The date is converted to the local timezone, based on the TimeOffset property in FtpClient. 598 | /// 599 | Local = 1, 600 | #endif 601 | /// 602 | /// The date is converted to UTC, based on the TimeOffset property in FtpClient. 603 | /// 604 | UTC = 2, 605 | } 606 | } --------------------------------------------------------------------------------