├── .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 | }
--------------------------------------------------------------------------------