├── FUNDING.yml
├── FluentFTP
├── restore.bat
├── sn.snk
├── Client
│ ├── Interfaces
│ │ └── IFtpLogger.cs
│ ├── BaseClient
│ │ ├── CanUploadFile.cs
│ │ ├── IsProxy.cs
│ │ ├── LoadProfile.cs
│ │ ├── Disconnect.cs
│ │ ├── ConvertDate.cs
│ │ ├── Connect.cs
│ │ ├── ValidateAutoDetect.cs
│ │ ├── ValidateCertficate.cs
│ │ ├── CheckFileExistsBySize.cs
│ │ ├── StartListeningOnPort.cs
│ │ └── Dispose.cs
│ ├── SyncClient
│ │ ├── GetWorkingDirectory.cs
│ │ ├── GetReply.cs
│ │ ├── Execute.cs
│ │ ├── DisableUTF8.cs
│ │ ├── Handshake.cs
│ │ ├── IsStillConnected.cs
│ │ ├── GetChmod.cs
│ │ ├── GetAbsoluteFilePath.cs
│ │ ├── GetAbsoluteDir.cs
│ │ ├── DeleteFile.cs
│ │ ├── SetWorkingDirectory.cs
│ │ ├── Disconnect.cs
│ │ ├── IsRoot.cs
│ │ ├── Noop.cs
│ │ ├── GetFilePermissions.cs
│ │ ├── GetModifiedTime.cs
│ │ ├── AutoConnect.cs
│ │ ├── SetDataType.cs
│ │ └── EmptyDirectory.cs
│ └── AsyncClient
│ │ ├── DisableUTF8.cs
│ │ ├── Handshake.cs
│ │ ├── GetAbsoluteFilePath.cs
│ │ ├── GetAbsoluteDir.cs
│ │ ├── GetReply.cs
│ │ ├── GetChmod.cs
│ │ ├── IsRoot.cs
│ │ ├── DeleteFile.cs
│ │ ├── SetWorkingDirectory.cs
│ │ ├── Disconnect.cs
│ │ ├── GetFilePermissions.cs
│ │ └── GetModifiedTime.cs
├── Proxy
│ ├── Enums
│ │ ├── SocksVersion.cs
│ │ ├── SocksRequestCommand.cs
│ │ ├── SocksRequestAddressType.cs
│ │ ├── SocksAuthType.cs
│ │ └── SocksReply.cs
│ ├── SyncProxy
│ │ ├── FtpClientProxy.cs
│ │ └── FtpClientUserAtHostProxy.cs
│ └── AsyncProxy
│ │ └── AsyncFtpClientUserAtHostProxy.cs
├── Streams
│ └── Interfaces
│ │ ├── IFtpStreamConfig.cs
│ │ └── IFtpStream.cs
├── Enums
│ ├── FtpObjectType.cs
│ ├── FtpDataType.cs
│ ├── FtpPermission.cs
│ ├── FtpSpecialPermissions.cs
│ ├── FtpIpVersion.cs
│ ├── FtpStatus.cs
│ ├── FtpFolderSyncMode.cs
│ ├── FtpsBuffering.cs
│ ├── FtpEncryptionMode.cs
│ ├── FtpTraceLevel.cs
│ ├── FtpResponseType.cs
│ ├── FtpHashAlgorithm.cs
│ ├── FtpObjectSubType.cs
│ ├── FtpConnectionState.cs
│ ├── FtpCompareResult.cs
│ ├── FtpZOSListRealm.cs
│ ├── FtpDate.cs
│ ├── FtpOperatingSystem.cs
│ ├── FtpVerifyMethod.cs
│ ├── FtpLocalExists.cs
│ ├── FtpOperator.cs
│ └── FtpCompareOption.cs
├── Events
│ └── FtpSocketStreamSslValidation.cs
├── Model
│ ├── FtpLogEntry.cs
│ ├── FtpSizeReply.cs
│ └── FtpProxyProfile.cs
├── Exceptions
│ ├── FtpProtocolUnsupportedException.cs
│ ├── FtpProxyException.cs
│ ├── FtpListParseException.cs
│ ├── FtpMissingSocketException.cs
│ ├── IOExceptions.cs
│ ├── FtpSecurityNotAvailableException.cs
│ ├── FtpAuthenticationException.cs
│ ├── FtpException.cs
│ └── FtpInvalidCertificateException.cs
├── Helpers
│ ├── Uris.cs
│ ├── TimeSpans.cs
│ ├── Logging
│ │ └── LoggerExtensions.cs
│ ├── LocalPorts.cs
│ └── Enums.cs
├── Servers
│ ├── Handlers
│ │ ├── DLinkServer.cs
│ │ ├── TPLinkServer.cs
│ │ ├── BFtpdServer.cs
│ │ ├── WSFTPServer.cs
│ │ ├── PyFtpdLibServer.cs
│ │ ├── CrushFtpServer.cs
│ │ ├── IDALFtpServer.cs
│ │ ├── TitanFtpServer.cs
│ │ ├── XLightServer.cs
│ │ ├── CerberusServer.cs
│ │ ├── HomegateFtpServer.cs
│ │ ├── Ftp2S3GatewayServer.cs
│ │ ├── GlobalScapeEftServer.cs
│ │ ├── RumpusServer.cs
│ │ ├── FritzBoxServer.cs
│ │ ├── GlFtpdServer.cs
│ │ ├── ApacheFtpServer.cs
│ │ ├── SolarisFtpServer.cs
│ │ ├── MicroTikServer.cs
│ │ ├── HuaweiServer.cs
│ │ ├── WindowsIISServer.cs
│ │ ├── WindowsCEServer.cs
│ │ ├── FileZillaServer.cs
│ │ ├── PureFtpdServer.cs
│ │ ├── VsFtpdServer.cs
│ │ └── NonStopTandemServer.cs
│ └── FtpHandlerIndex.cs
└── Rules
│ └── FtpRule.cs
├── FluentFTP.Dockers
├── pyftpdlib
│ ├── requirements.txt
│ ├── Dockerfile
│ └── LICENSE
├── filezilla
│ ├── run-filezilla.sh
│ ├── get-filezilla.sh
│ ├── docker-compose.yml
│ └── users.xml
├── glftpd
│ ├── xinetd_glftpd.conf
│ ├── docker-compose.yml
│ ├── xinetd.conf
│ └── run-glftpd.sh
├── bftpd
│ ├── docker-compose.yml
│ ├── run-bftpd.sh
│ └── Dockerfile
├── vsftpd
│ ├── docker-compose.yml
│ └── run-vsftpd.sh
├── apache
│ ├── docker-compose.yml
│ ├── run-apache.sh
│ └── users.properties
├── common-debian-slim
│ └── Dockerfile
├── proftpd
│ ├── docker-compose.yml
│ └── run-proftpd.sh
├── pureftpd
│ ├── docker-compose.yml
│ ├── run-pureftpd.sh
│ └── Dockerfile
├── common-mirror
│ └── Dockerfile
└── common-debian
│ └── Dockerfile
├── FluentFTP.Logging
├── restore.bat
├── sn.snk
├── RELEASES.md
├── README.md
└── FtpLogAdapter.cs
├── .github
├── gnutls.png
├── logging.png
├── gnutls-2.png
├── logo-new.png
├── features-5.png
├── ftp-monitor.png
├── logo-nuget.png
├── yourkit-logo.png
├── auto-reconnect.png
├── balsamiq-logo.png
├── contributors-3.png
├── jetbrains-logo.png
└── workflows_WIP
│ └── pull_request.yml
├── FluentFTP.Tests
├── config.yaml.template
├── Unit
│ ├── ExceptionTests.cs
│ ├── HelperTests.cs
│ └── IsProxyTests.cs
└── Integration
│ └── System
│ └── IntegrationTestRunner.cs
├── FluentFTP.Xunit
├── Attributes
│ ├── SkippableState.cs
│ ├── SkipTestException.cs
│ ├── SkippableFactAttribute.cs
│ ├── SkippableTheoryAttribute.cs
│ └── Internal
│ │ ├── SkippableFactDiscoverer.cs
│ │ └── SkippableFactMessageBus.cs
├── Docker
│ ├── DockerFtpConfig.cs
│ ├── DockerFtpContainerIndex.cs
│ └── Containers
│ │ ├── BFtpdContainer.cs
│ │ ├── ApacheContainer.cs
│ │ ├── GlFtpdContainer.cs
│ │ ├── FileZillaContainer.cs
│ │ ├── ProFtpdContainer.cs
│ │ ├── PyFtpdLibContainer.cs
│ │ └── VsFtpdContainer.cs
└── FluentFTP.Xunit.csproj
├── .gitignore
├── FluentFTP.VBExamples
├── VBExamples.vbproj
├── DeleteFile.vb
├── SetWorkingDirectory.vb
├── CreateDirectory.vb
├── GetWorkingDirectory.vb
├── GetFileSize.vb
├── ConnectFTPS.vb
├── FileExists.vb
├── GetModifiedTime.vb
├── DirectoryExists.vb
├── DeleteDirectory.vb
├── Rename.vb
├── GetNameListing.vb
├── Connect.vb
├── FolderMonitor.vb
├── ConnectFTPSCertificate.vb
├── UploadManyFiles.vb
├── DownloadManyFiles.vb
├── DownloadDirectory.vb
├── UploadDirectory.vb
└── DownloadFile.vb
├── appveyor.yml
├── FluentFTP.CSharpExamples
├── Extensions.cs
├── DeleteFile.cs
├── Log_NLog.cs
├── SetWorkingDirectory.cs
├── CreateDirectory.cs
├── GetWorkingDirectory.cs
├── DirectoryExists.cs
├── GetFileSize.cs
├── ConnectFTPS.cs
├── DeleteDirectory.cs
├── GetModifiedTime.cs
├── Log_Serilog.cs
├── CSharpExamples.csproj
├── ExecuteFTPCommand.cs
├── FileExists.cs
├── Rename.cs
├── Connect.cs
├── GetNameListing.cs
├── ConnectFTPSCertificate.cs
├── UploadManyFiles.cs
├── DownloadManyFiles.cs
└── DownloadDirectory.cs
├── ISSUE_TEMPLATE.md
└── LICENSE.TXT
/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: robinrodricks
2 |
--------------------------------------------------------------------------------
/FluentFTP/restore.bat:
--------------------------------------------------------------------------------
1 | dotnet restore FluentFTP.csproj
2 | pause
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pyftpdlib/requirements.txt:
--------------------------------------------------------------------------------
1 | pyftpdlib==1.5.6
2 |
--------------------------------------------------------------------------------
/FluentFTP.Logging/restore.bat:
--------------------------------------------------------------------------------
1 | dotnet restore FluentFTP.Logging.csproj
2 | pause
--------------------------------------------------------------------------------
/FluentFTP/sn.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/FluentFTP/sn.snk
--------------------------------------------------------------------------------
/.github/gnutls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/gnutls.png
--------------------------------------------------------------------------------
/.github/logging.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/logging.png
--------------------------------------------------------------------------------
/.github/gnutls-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/gnutls-2.png
--------------------------------------------------------------------------------
/.github/logo-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/logo-new.png
--------------------------------------------------------------------------------
/.github/features-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/features-5.png
--------------------------------------------------------------------------------
/.github/ftp-monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/ftp-monitor.png
--------------------------------------------------------------------------------
/.github/logo-nuget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/logo-nuget.png
--------------------------------------------------------------------------------
/.github/yourkit-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/yourkit-logo.png
--------------------------------------------------------------------------------
/FluentFTP.Logging/sn.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/FluentFTP.Logging/sn.snk
--------------------------------------------------------------------------------
/.github/auto-reconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/auto-reconnect.png
--------------------------------------------------------------------------------
/.github/balsamiq-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/balsamiq-logo.png
--------------------------------------------------------------------------------
/.github/contributors-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/contributors-3.png
--------------------------------------------------------------------------------
/.github/jetbrains-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/.github/jetbrains-logo.png
--------------------------------------------------------------------------------
/FluentFTP.Logging/RELEASES.md:
--------------------------------------------------------------------------------
1 | ### 1.0.0
2 |
3 | - Introduced `FtpLogAdapter` to integrate FluentFTP with MELA.
4 |
--------------------------------------------------------------------------------
/FluentFTP.Tests/config.yaml.template:
--------------------------------------------------------------------------------
1 | server:
2 | host: 1.2.3.4
3 | port: 21
4 | user: ftpuser
5 | pass: ftppass
--------------------------------------------------------------------------------
/FluentFTP.Dockers/filezilla/run-filezilla.sh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhamedHabib/FluentFTP/master/FluentFTP.Dockers/filezilla/run-filezilla.sh
--------------------------------------------------------------------------------
/FluentFTP/Client/Interfaces/IFtpLogger.cs:
--------------------------------------------------------------------------------
1 | namespace FluentFTP {
2 | public interface IFtpLogger {
3 | void Log(FtpLogEntry entry);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/CanUploadFile.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Helpers;
2 |
3 | namespace FluentFTP.Client.BaseClient {
4 | public partial class BaseFtpClient {
5 |
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/FluentFTP/Proxy/Enums/SocksVersion.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace FluentFTP.Proxy.Enums {
7 | internal enum SocksVersion {
8 | V4 = 0x04,
9 | V5 = 0x05
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/FluentFTP/Streams/Interfaces/IFtpStreamConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP.Streams {
8 | public interface IFtpStreamConfig {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/FluentFTP.Logging/README.md:
--------------------------------------------------------------------------------
1 | # FluentFTP.Logging
2 |
3 | Logging adapter to help FluentFTP integrate with MELA-compatible Loggers (NLog, Serilog, Log4Net, PLogger, etc).
4 |
5 | Read the [Logging](https://github.com/robinrodricks/FluentFTP/wiki/Logging) page to learn how to use this library.
--------------------------------------------------------------------------------
/FluentFTP/Proxy/Enums/SocksRequestCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace FluentFTP.Proxy.Enums {
7 | internal enum SocksRequestCommand : byte {
8 | Connect = 0x01,
9 | Bind = 0x02,
10 | UdpAssociate = 0x03
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/SkippableState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP.Xunit.Attributes {
8 | internal static class SkippableState {
9 | internal static bool ShouldSkip { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/FluentFTP/Proxy/Enums/SocksRequestAddressType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace FluentFTP.Proxy.Enums {
7 | internal enum SocksRequestAddressType {
8 | Unknown = 0x00,
9 | IPv4 = 0x01,
10 | FQDN = 0x03,
11 | IPv6 = 0x04
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/filezilla/get-filezilla.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | wget -O tempfile $1
4 |
5 | STEP2=$(cat tempfile | grep linux-gnu.deb)
6 | echo " "
7 | echo $STEP2
8 |
9 | rm tempfile
10 |
11 | STEP3=$(echo $STEP2 | grep -P -o '(?<=a href=").*?(?=")')
12 | echo " "
13 | echo $STEP3
14 |
15 | wget -O FileZilla-Server.deb $STEP3
16 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/glftpd/xinetd_glftpd.conf:
--------------------------------------------------------------------------------
1 | service glftpd
2 | {
3 | disable = no
4 | flags = REUSE IPv6
5 | socket_type = stream
6 | protocol = tcp
7 | wait = no
8 | user = root
9 | server = /glftpd/bin/glftpd
10 | server_args = -l -i -o -e
11 | }
12 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pyftpdlib/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10-slim
2 |
3 | MAINTAINER Andriy Kogut "kogut.andriy@gmail.com"
4 |
5 | COPY . /app
6 | WORKDIR /app
7 | RUN pip install -r requirements.txt
8 |
9 | RUN mkdir /ftp_root
10 | RUN mkdir /ftp_root/nobody
11 | RUN mkdir /ftp_root/user
12 |
13 | EXPOSE 20 21
14 |
15 | CMD python ftpd.py
16 |
--------------------------------------------------------------------------------
/FluentFTP/Proxy/Enums/SocksAuthType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace FluentFTP.Proxy.Enums {
7 | internal enum SocksAuthType {
8 | NoAuthRequired = 0x00,
9 | GSSAPI = 0x01,
10 | UsernamePassword = 0x02,
11 | NoAcceptableMethods = 0xFF
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/glftpd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | glftpd:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | ports:
8 | - 0.0.0.0:20:20
9 | - 0.0.0.0:21:21
10 | - 21100-21110:21100-21199
11 | volumes:
12 | - ./home:/home/glftpd
13 | - ./logs:/var/log/glftpd
14 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/SkipTestException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP.Xunit.Attributes {
8 | public class SkipTestException : Exception {
9 | public SkipTestException(string reason)
10 | : base(reason) { }
11 | }
12 | }
--------------------------------------------------------------------------------
/FluentFTP.Dockers/bftpd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | bftpd:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | restart: always
8 | ports:
9 | - 0.0.0.0:20:20
10 | - 0.0.0.0:21:21
11 | - 21100-21199:21100-21199
12 | volumes:
13 | - ./home:/home/bftpd
14 | - ./logs:/var/log/bftpd
15 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/vsftpd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | vsftpd:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | restart: always
8 | ports:
9 | - 0.0.0.0:20:20
10 | - 0.0.0.0:21:21
11 | - 21100-21199:21100-21199
12 | volumes:
13 | - ./home:/home/vsftpd
14 | - ./logs:/var/log/vsftpd
15 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/apache/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | apache:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | restart: always
8 | network_mode: "host"
9 | ports:
10 | - 0.0.0.0:20:20
11 | - 0.0.0.0:21:21
12 | - 21100-21199:21100-21199
13 | volumes:
14 | - ./home:/home/apache
15 | - ./logs:/var/log/apache
16 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/common-debian-slim/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # FluentFTP Integration Test: Debian Run Image
3 | #
4 |
5 | FROM debian:bullseye-slim AS build
6 |
7 | SHELL ["/bin/bash", "-c"]
8 |
9 | ARG DEBIAN_FRONTEND=noninteractive
10 | ARG APT_CMD='apt install -y --no-install-recommends'
11 |
12 | COPY sources.list /etc/apt/sources.list
13 |
14 | RUN apt update && apt upgrade -y
15 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/proftpd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | proftpd:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | restart: always
8 | network_mode: "host"
9 | ports:
10 | - 0.0.0.0:20:20
11 | - 0.0.0.0:21:21
12 | - 21100-21199:21100-21199
13 | volumes:
14 | - ./home:/home/proftpd
15 | - ./logs:/var/log/proftpd
16 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pureftpd/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | pureftpd:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | restart: always
8 | network_mode: "host"
9 | ports:
10 | - 0.0.0.0:20:20
11 | - 0.0.0.0:21:21
12 | - 21100-21199:21100-21199
13 | volumes:
14 | - ./home:/home/pureftpd
15 | - ./logs:/var/log/pureftpd
16 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/filezilla/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | filezilla:
3 | build:
4 | context: .
5 | network: host
6 | restart: unless-stopped
7 | ports:
8 | - 0.0.0.0:20:20
9 | - 0.0.0.0:21:21
10 | - 0.0.0.0:14149:14149
11 | - 21100-21110:21100-21199
12 | volumes:
13 | - ./home:/home/filezilla
14 | - ./logs:/var/log/filezilla
15 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/common-mirror/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # FluentFTP Integration Test: Debian Mirror Selection
3 | #
4 |
5 | FROM python:3.10-slim AS prebuild
6 |
7 | SHELL ["/bin/bash", "-c"]
8 |
9 | WORKDIR /usr/src/app
10 | RUN pip install --user apt-smart
11 |
12 | COPY run.sh /usr/bin/
13 |
14 | RUN sed -i -e "s/\r//" /usr/bin/run.sh && \
15 | chmod +x /usr/bin/run.sh
16 |
17 | CMD ["/usr/bin/run.sh"]
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/SkippableFactAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 | using Xunit.Sdk;
8 |
9 | namespace FluentFTP.Xunit.Attributes {
10 | [XunitTestCaseDiscoverer("FluentFTP.Xunit.Attributes.Internal.SkippableFactDiscoverer", "FluentFTP.Xunit")]
11 | public class SkippableFactAttribute : FactAttribute { }
12 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpObjectType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Type of file system of object
6 | ///
7 | public enum FtpObjectType {
8 | ///
9 | /// A file
10 | ///
11 | File,
12 |
13 | ///
14 | /// A directory
15 | ///
16 | Directory,
17 |
18 | ///
19 | /// A symbolic link
20 | ///
21 | Link
22 | }
23 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/SkippableTheoryAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 | using Xunit.Sdk;
8 |
9 | namespace FluentFTP.Xunit.Attributes {
10 | [XunitTestCaseDiscoverer("FluentFTP.Xunit.Attributes.Internal.SkippableTheoryDiscoverer", "FluentFTP.Xunit")]
11 | public class SkippableTheoryAttribute : TheoryAttribute { }
12 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpDataType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Type of data transfer to do
6 | ///
7 | public enum FtpDataType {
8 | ///
9 | /// ASCII transfer
10 | ///
11 | ASCII,
12 |
13 | ///
14 | /// Binary transfer
15 | ///
16 | Binary,
17 |
18 | ///
19 | /// Not known yet
20 | ///
21 | Unknown
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/IsProxy.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using FluentFTP.Proxy.AsyncProxy;
3 | using FluentFTP.Proxy.SyncProxy;
4 |
5 | namespace FluentFTP.Client.BaseClient {
6 | public partial class BaseFtpClient {
7 |
8 | ///
9 | /// Checks if this FTP/FTPS connection is made through a proxy.
10 | ///
11 | public bool IsProxy() {
12 | return this is FtpClientProxy or AsyncFtpClientProxy;
13 | }
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.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 |
25 | FluentFTP.Tests/testdata
26 | *.yaml
27 | /Powershell/FluentFTP.dll
28 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/VBExamples.vbproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Library
6 | latest
7 |
8 |
9 | AnyCPU;x64
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/common-debian/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # FluentFTP Integration Test: Debian Build Image
3 | #
4 |
5 | FROM debian:bullseye-slim AS build
6 |
7 | SHELL ["/bin/bash", "-c"]
8 |
9 | ARG DEBIAN_FRONTEND=noninteractive
10 | ARG APT_CMD='apt install -y --no-install-recommends'
11 |
12 | COPY sources.list /etc/apt/sources.list
13 |
14 | RUN apt update && apt upgrade -y && apt install -y apt-utils && \
15 | \
16 | $APT_CMD \
17 | ca-certificates \
18 | wget \
19 | build-essential
20 |
--------------------------------------------------------------------------------
/FluentFTP/Events/FtpSocketStreamSslValidation.cs:
--------------------------------------------------------------------------------
1 | namespace FluentFTP {
2 |
3 | ///
4 | /// Event fired if a bad SSL certificate is encountered. This even is used internally; if you
5 | /// don't have a specific reason for using it you are probably looking for FtpSslValidation.
6 | ///
7 | ///
8 | ///
9 | public delegate void FtpSocketStreamSslValidation(FtpSocketStream stream, FtpSslValidationEventArgs e);
10 |
11 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/LoadProfile.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.Modules;
2 |
3 | namespace FluentFTP.Client.BaseClient {
4 | public partial class BaseFtpClient {
5 |
6 | ///
7 | /// Load the given connection profile and configure the FTP client instance accordingly.
8 | ///
9 | /// Connection profile. Not modified.
10 | public void LoadProfile(FtpProfile profile) {
11 | ConnectModule.LoadProfile(this, profile);
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 |
20 | dotnet test fluentftp.tests -f netcoreapp1.0
21 |
22 | artifacts:
23 | - path: '**\*.nupkg'
24 |
--------------------------------------------------------------------------------
/FluentFTP/Model/FtpLogEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Metadata of a single log message.
6 | ///
7 | public readonly struct FtpLogEntry {
8 | public FtpTraceLevel Severity { get; }
9 | public string Message { get; }
10 | public Exception Exception { get; }
11 |
12 | public FtpLogEntry(FtpTraceLevel severity, string msg, Exception ex = null) {
13 | Severity = severity;
14 | Message = msg;
15 | Exception = ex;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/FluentFTP/Model/FtpSizeReply.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 |
7 | ///
8 | /// Reply from a SIZE command
9 | ///
10 | public class FtpSizeReply {
11 |
12 | ///
13 | /// The returned file size
14 | ///
15 | public long FileSize { get; set; }
16 |
17 | ///
18 | /// The reply we got
19 | ///
20 | public FtpReply Reply { get; set; }
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/FluentFTP/Proxy/Enums/SocksReply.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace FluentFTP.Proxy.Enums {
7 | internal enum SocksReply {
8 | Succeeded = 0x00,
9 | GeneralSOCKSServerFailure = 0x01,
10 | NotAllowedByRuleset = 0x02,
11 | NetworkUnreachable = 0x03,
12 | HostUnreachable = 0x04,
13 | ConnectionRefused = 0x05,
14 | TTLExpired = 0x06,
15 | CommandNotSupported = 0x07,
16 | AddressTypeNotSupported = 0x08
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/glftpd/xinetd.conf:
--------------------------------------------------------------------------------
1 | # Simple configuration file for xinetd
2 | #
3 | # Some defaults, and include /etc/xinetd.d/
4 |
5 | defaults
6 | {
7 |
8 | # Please note that you need a log_type line to be able to use log_on_success
9 | # and log_on_failure. The default is the following :
10 | # log_type = SYSLOG daemon info
11 |
12 | log_type = FILE /var/log/xinetdlog
13 | log_on_success = HOST PID
14 | log_on_failure = HOST
15 | }
16 |
17 | includedir /etc/xinetd.d
18 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpPermission.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Types of file permissions
6 | ///
7 | [Flags]
8 | public enum FtpPermission : uint {
9 | ///
10 | /// No access
11 | ///
12 | None = 0,
13 |
14 | ///
15 | /// Executable
16 | ///
17 | Execute = 1,
18 |
19 | ///
20 | /// Writable
21 | ///
22 | Write = 2,
23 |
24 | ///
25 | /// Readable
26 | ///
27 | Read = 4
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP.Dockers/bftpd/run-bftpd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp bftpd *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | EOB
16 |
17 | # Run bftpd:
18 | &>/dev/null /usr/sbin/bftpd -c /usr/etc/bftpd.conf -D
19 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/apache/run-apache.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp apache *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | EOB
16 |
17 | # Run apache:
18 | cd /root/apache
19 | bin/ftpd.sh res/conf/config.xml
20 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetWorkingDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace FluentFTP {
9 | public partial class FtpClient {
10 |
11 | ///
12 | /// Gets the current working directory
13 | ///
14 | /// The current working directory, ./ if the response couldn't be parsed.
15 | public string GetWorkingDirectory() {
16 | return ((IInternalFtpClient)this).GetWorkingDirectoryInternal();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpSpecialPermissions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Types of special UNIX permissions
6 | ///
7 | [Flags]
8 | public enum FtpSpecialPermissions : int {
9 | ///
10 | /// No special permissions are set
11 | ///
12 | None = 0,
13 |
14 | ///
15 | /// Sticky bit is set
16 | ///
17 | Sticky = 1,
18 |
19 | ///
20 | /// SGID bit is set
21 | ///
22 | SetGroupID = 2,
23 |
24 | ///
25 | /// SUID bit is set
26 | ///
27 | SetUserID = 4
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/DockerFtpConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP.Xunit.Docker {
8 | public static class DockerFtpConfig {
9 |
10 | ///
11 | /// Detect if running inside GitHub Actions CI pipeline.
12 | ///
13 | public static bool IsCI = string.Equals(Environment.GetEnvironmentVariable("CI"), "true", StringComparison.OrdinalIgnoreCase);
14 |
15 | public static string FtpUser = "fluentuser";
16 |
17 | public static string FtpPass = "fluentpass";
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpProtocolUnsupportedException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 |
8 | ///
9 | /// FtpProtocolUnsupportedException
10 | ///
11 | #if NETFRAMEWORK
12 | [Serializable]
13 | #endif
14 | public class FtpProtocolUnsupportedException : FtpException {
15 |
16 | ///
17 | /// FtpProtocolUnsupportedException
18 | ///
19 | /// Error message
20 | public FtpProtocolUnsupportedException(string message)
21 | : base(message) {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/Disconnect.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Client.BaseClient {
5 |
6 | public partial class BaseFtpClient {
7 |
8 | ///
9 | /// Disconnects from the server
10 | ///
11 | void IInternalFtpClient.DisconnectInternal() {
12 | ((IFtpClient)this).Disconnect();
13 | }
14 |
15 | ///
16 | /// Disconnects from the server asynchronously
17 | ///
18 | async Task IInternalFtpClient.DisconnectInternal(CancellationToken token) {
19 | await ((IAsyncFtpClient)this).Disconnect(token);
20 | }
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetReply.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using System.Threading;
3 |
4 | namespace FluentFTP {
5 | public partial class FtpClient {
6 |
7 | ///
8 | /// Retrieves a reply from the server.
9 | /// Support "normal" mode waiting for a command reply, subject to timeout exception
10 | /// and "exhaustNoop" mode, which waits for 10 seconds to collect out of band NOOP responses
11 | ///
12 | /// FtpReply representing the response from the server
13 | public FtpReply GetReply() {
14 | return ((IInternalFtpClient)this).GetReplyInternal(null, false, 0);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpIpVersion.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// IP Versions to allow when connecting
6 | /// to a server.
7 | ///
8 | [Flags]
9 | public enum FtpIpVersion : int {
10 |
11 | ///
12 | /// Unknown protocol.
13 | ///
14 | Unknown = 0,
15 |
16 | ///
17 | /// Internet Protocol Version 4
18 | ///
19 | IPv4 = 1,
20 |
21 | ///
22 | /// Internet Protocol Version 6
23 | ///
24 | IPv6 = 2,
25 |
26 | ///
27 | /// Allow any supported version
28 | ///
29 | ANY = IPv4 | IPv6
30 | }
31 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/Extensions.cs:
--------------------------------------------------------------------------------
1 | namespace Examples {
2 | internal static class Extensions {
3 | public static string FormatBytes(this long val) {
4 | return ((double)val).FormatBytes();
5 | }
6 |
7 | public static string FormatBytes(this int val) {
8 | return ((double)val).FormatBytes();
9 | }
10 |
11 | public static string FormatBytes(this double val) {
12 | var units = new[] { "B", "KB", "MB", "GB", "TB" };
13 | var count = 0;
14 |
15 | while (count + 1 < units.Length && val >= 1024) {
16 | count += 1;
17 | val /= 1024;
18 | }
19 |
20 | return string.Format("{0:0.00} {1}", val, units[count]);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/FluentFTP.Tests/Unit/ExceptionTests.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 | using FluentFTP.Helpers;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using Xunit;
7 |
8 | namespace FluentFTP.Tests.Unit {
9 | public class ExceptionTests {
10 |
11 | [Fact]
12 | public void FtpCommandException_includes_CompletionCode_in_message() {
13 |
14 | Action act = () => throw new FtpCommandException("501", "MyErrorMessage");
15 |
16 | var exception = Assert.Throws(act);
17 | Assert.Contains("501", exception.ToString());
18 | Assert.Contains("MyErrorMessage", exception.ToString());
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/DockerFtpContainerIndex.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Xunit.Docker.Containers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace FluentFTP.Xunit.Docker {
9 | internal static class DockerFtpContainerIndex {
10 |
11 | public static List Index = new List {
12 | new ApacheContainer(),
13 | new BFtpdContainer(),
14 | new FileZillaContainer(),
15 | new GlFtpdContainer(),
16 | new ProFtpdContainer(),
17 | new PureFtpdContainer(),
18 | new PyFtpdLibContainer(),
19 | new VsFtpdContainer(),
20 | };
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/Execute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Net.Sockets;
4 | using System.Text.RegularExpressions;
5 | using System.Linq;
6 | using System.Net;
7 | using FluentFTP.Helpers;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace FluentFTP {
12 | public partial class FtpClient {
13 |
14 | ///
15 | /// Executes a command
16 | ///
17 | /// The command to execute
18 | /// The servers reply to the command
19 | public FtpReply Execute(string command) {
20 | return ((IInternalFtpClient)this).ExecuteInternal(command);
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/FluentFTP.Dockers/proftpd/run-proftpd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp proftpd *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | · SSL: $USE_SSL
16 | EOB
17 |
18 | if [[ -n "${USE_SSL}" ]]; then
19 | sed -i "s/^\(# \)\?TLSEngine.*$/TLSEngine on/" /etc/proftpd/tls.conf
20 | fi
21 |
22 | # Run proftpd:
23 | &>/dev/null /usr/sbin/proftpd -n
24 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pureftpd/run-pureftpd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp pureftpd *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | · SSL: $USE_SSL
16 | EOB
17 |
18 | if [[ -n "${USE_SSL}" ]]; then
19 | TLS=1
20 | else
21 | TLS=0
22 | fi
23 |
24 | # Run pureftpd:
25 | &>/dev/null /usr/sbin/pure-ftpd -A -E -j -R -l unix -p 21100:21199 --tls $TLS
26 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/vsftpd/run-vsftpd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp vsftpd *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | · SSL: $USE_SSL
16 | EOB
17 |
18 | if [[ -n "${USE_SSL}" ]]; then
19 | sed -i "s/^\(# \)\?ssl_enable=.*$/ssl_enable=YES/" /etc/vsftpd.conf
20 | fi
21 |
22 | # Run vsftpd:
23 | &>/dev/null /usr/sbin/vsftpd /etc/vsftpd.conf
24 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/DisableUTF8.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 |
3 |
4 |
5 | using System.Text;
6 |
7 | namespace FluentFTP {
8 | public partial class FtpClient {
9 |
10 | ///
11 | /// Disables UTF8 support and changes the Encoding property
12 | /// back to ASCII. If the server returns an error when trying
13 | /// to turn UTF8 off a FtpCommandException will be thrown.
14 | ///
15 | public void DisableUTF8() {
16 | FtpReply reply;
17 |
18 | reply = Execute("OPTS UTF8 OFF");
19 |
20 | if (!reply.Success) {
21 | throw new FtpCommandException(reply);
22 | }
23 |
24 | m_textEncoding = Encoding.ASCII;
25 | m_textEncodingAutoUTF = false;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 | ///
7 | /// The result of an upload or download operation
8 | ///
9 | public enum FtpStatus {
10 |
11 | ///
12 | /// The upload or download failed with an error transferring, or the source file did not exist
13 | ///
14 | Failed = 0,
15 |
16 | ///
17 | /// The upload or download completed successfully
18 | ///
19 | Success = 1,
20 |
21 | ///
22 | /// The upload or download was skipped because the file already existed on the target
23 | ///
24 | Skipped = 2
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpProxyException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP.Exceptions {
4 |
5 | ///
6 | /// FtpProxyException
7 | ///
8 | public class FtpProxyException : FtpException {
9 |
10 | ///
11 | /// FtpProxyException
12 | ///
13 | public FtpProxyException() : base("Exception with a FTP proxy server.") {
14 | }
15 |
16 | ///
17 | /// FtpProxyException
18 | ///
19 | public FtpProxyException(string message)
20 | : base(message) {
21 | }
22 |
23 | ///
24 | /// FtpProxyException
25 | ///
26 | public FtpProxyException(string message, Exception inner)
27 | : base(message, inner) {
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/FluentFTP.Tests/Unit/HelperTests.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Helpers;
2 | using FluentFTP.Model.Functions;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Net;
7 | using System.Net.Sockets;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 | using Xunit.Sdk;
11 |
12 | namespace FluentFTP.Tests.Unit {
13 | public class HelperTests {
14 |
15 | [Fact]
16 | public void ValuePrinterTest() {
17 |
18 | var obj = new FtpAutoDetectConfig();
19 | var txt = ValuePrinter.ObjectToString(obj);
20 |
21 | Assert.Equal("CloneConnection = True, FirstOnly = True, IncludeImplicit = True, AbortOnTimeout = True, RequireEncryption = False, ProtocolPriority = [Tls12]", txt);
22 | }
23 |
24 | }
25 | }
--------------------------------------------------------------------------------
/FluentFTP/Streams/Interfaces/IFtpStream.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.BaseClient;
2 | using System.IO;
3 | using System.Net.Sockets;
4 | using System.Security.Authentication;
5 |
6 | namespace FluentFTP.Streams {
7 | public interface IFtpStream {
8 |
9 | void Init(
10 | BaseFtpClient client,
11 | string targetHost,
12 | Socket socket,
13 | CustomRemoteCertificateValidationCallback customRemoteCertificateValidation,
14 | bool isControl,
15 | IFtpStream controlConnStream,
16 | IFtpStreamConfig config);
17 |
18 | Stream GetBaseStream();
19 |
20 | bool CanRead();
21 | bool CanWrite();
22 |
23 | SslProtocols GetSslProtocol();
24 | string GetCipherSuite();
25 |
26 | void Dispose();
27 |
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/FluentFTP/Helpers/Uris.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP.Helpers {
4 | ///
5 | /// Extension methods related to FTP tasks
6 | ///
7 | internal static class Uris {
8 | ///
9 | /// Ensures that the URI points to a server, and not a directory or invalid path.
10 | ///
11 | ///
12 | public static void ValidateFtpServer(this Uri uri) {
13 | if (string.IsNullOrEmpty(uri.PathAndQuery)) {
14 | throw new UriFormatException("The supplied URI does not contain a valid path.");
15 | }
16 |
17 | if (uri.PathAndQuery.EndsWith("/")) {
18 | throw new UriFormatException("The supplied URI points at a directory.");
19 | }
20 | }
21 |
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/Handshake.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 | using System;
3 | using System.IO;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class FtpClient {
9 |
10 | ///
11 | /// Called during Connect(). Typically extended by FTP proxies.
12 | ///
13 | protected virtual void Handshake() {
14 | FtpReply reply;
15 | if (!(reply = GetReply()).Success) {
16 | if (reply.Code == null) {
17 | throw new IOException("The connection was terminated before a greeting could be read.");
18 | }
19 | else {
20 | throw new FtpCommandException(reply);
21 | }
22 | }
23 |
24 | HandshakeReply = reply;
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpFolderSyncMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 | ///
7 | /// Determines how we handle downloading and uploading folders
8 | ///
9 | public enum FtpFolderSyncMode {
10 |
11 | ///
12 | /// Dangerous but useful method!
13 | /// Uploads/downloads all the missing files to update the server/local filesystem.
14 | /// Deletes the extra files to ensure that the target is an exact mirror of the source.
15 | ///
16 | Mirror,
17 |
18 | ///
19 | /// Safe method!
20 | /// Uploads/downloads all the missing files to update the server/local filesystem.
21 | ///
22 | Update,
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/ConvertDate.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.Modules;
2 | using System;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace FluentFTP.Client.BaseClient {
7 |
8 | public partial class BaseFtpClient {
9 |
10 | ///
11 | /// If `reverse` is false, converts the date provided by the FTP server into the timezone required locally.
12 | /// If `reverse` is true, converts the local timezone date into the date required by the FTP server.
13 | ///
14 | /// Affected by properties: TimeConversion, ServerTimeZone, ClientTimeZone.
15 | ///
16 | public DateTime ConvertDate(DateTime date, bool reverse = false) {
17 | return TimezoneModule.ConvertDate(date, Config, reverse);
18 | }
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/IsStillConnected.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP {
7 | public partial class FtpClient {
8 |
9 | ///
10 | /// Performs a series of tests to check if we are still connected to the FTP server.
11 | /// More thourough than IsConnected.
12 | ///
13 | /// How to wait for connection confirmation
14 | /// bool connection status
15 | public bool IsStillConnected(int timeout = 10000) {
16 | LogFunction(nameof(IsStillConnected), new object[] { timeout });
17 |
18 | return ((IInternalFtpClient)this).IsStillConnectedInternal(timeout);
19 | }
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpsBuffering.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Determines how SSL Buffering is handled
6 | ///
7 | public enum FtpsBuffering {
8 | ///
9 | /// Enables SSL Buffering to massively speed up FTPS operations except when:
10 | /// Under .NET 5.0 and later due to platform issues (see issue 682 in FluentFTP issue tracker).
11 | /// On the control connection
12 | /// For proxy connections
13 | /// If NOOPs are configured to be used
14 | ///
15 | Auto,
16 |
17 | ///
18 | /// Always disables SSL Buffering to reduce FTPS connectivity issues.
19 | ///
20 | Off,
21 |
22 | ///
23 | /// Same as "Auto"
24 | ///
25 | On
26 | }
27 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DeleteFile.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module DeleteFileExample
9 | Sub DeleteFile()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | conn.DeleteFile("/full/or/relative/path/to/file")
13 | End Using
14 | End Sub
15 |
16 | Async Function DeleteDirectoryAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Await conn.DeleteFile("/full/or/relative/path/to/file")
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/DeleteFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class DeleteFileExample {
9 |
10 | public static void DeleteFile() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | conn.DeleteFile("/full/or/relative/path/to/file");
15 | }
16 | }
17 |
18 | public static async Task DeleteDirectoryAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 | await conn.Connect(token);
22 |
23 | await conn.DeleteFile("/full/or/relative/path/to/file", token);
24 | }
25 | }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetChmod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP {
7 | public partial class FtpClient {
8 |
9 | ///
10 | /// Retrieve the permissions of the given file/folder as an integer in the CHMOD format.
11 | /// Throws FtpCommandException if there is an issue.
12 | /// Returns 0 if the server did not specify a permission value.
13 | /// Use `GetFilePermissions` if you required the permissions in the FtpPermission format.
14 | ///
15 | /// The full or relative path to the item
16 | public int GetChmod(string path) {
17 | var item = GetFilePermissions(path);
18 | return item != null ? item.Chmod : 0;
19 | }
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/Log_NLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using FluentFTP;
4 | using FluentFTP.Logging;
5 | using NLog.Extensions.Logging;
6 |
7 | namespace Examples {
8 | internal static class NLogExample {
9 |
10 | public static void Configure() {
11 |
12 | using (var conn = new FtpClient()) {
13 | conn.Host = "localhost";
14 | conn.Credentials = new NetworkCredential("ftptest", "ftptest");
15 |
16 |
17 | // create NLog logger
18 | var nlogLogger = new NLogLoggerProvider();
19 |
20 | // wrap with MELA ILogger
21 | var microsoftLogger = nlogLogger.CreateLogger(typeof(Log4NetExample).FullName);
22 |
23 | // wrap with FtpLogAdapter
24 | conn.Logger = new FtpLogAdapter(microsoftLogger);
25 |
26 |
27 | conn.Connect();
28 | }
29 | }
30 |
31 | }
32 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetAbsoluteFilePath.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FluentFTP.Helpers;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class FtpClient {
9 |
10 | ///
11 | /// Concat a path and a filename
12 | ///
13 | protected string GetAbsoluteFilePath(string path, string fileName) {
14 | string filePath = null;
15 | if (ServerHandler != null && ServerHandler.IsCustomGetAbsoluteFilePath()) {
16 | filePath = ServerHandler.GetAbsoluteFilePath(this, path, fileName);
17 | }
18 |
19 | if (filePath != null) {
20 | return filePath;
21 | }
22 |
23 | path = !path.EndsWith("/") ? path + "/" + fileName : path + fileName;
24 |
25 | return path;
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpEncryptionMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Defines the type of encryption to use
6 | ///
7 | public enum FtpEncryptionMode {
8 | ///
9 | /// Plain text.
10 | ///
11 | None,
12 |
13 | ///
14 | /// FTPS encryption is used from the start of the connection, port 990.
15 | ///
16 | Implicit,
17 |
18 | ///
19 | /// Connection starts in plain text and FTPS encryption is enabled
20 | /// with the AUTH command immediately after the server greeting.
21 | ///
22 | Explicit,
23 |
24 | ///
25 | /// FTPS encryption is used if supported by the server, otherwise it falls back to plaintext FTP communication.
26 | ///
27 | Auto
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/SetWorkingDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module SetWorkingDirectoryExample
9 | Sub SetWorkingDirectory()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | conn.SetWorkingDirectory("/full/or/relative/path")
13 | End Using
14 | End Sub
15 |
16 | Async Function SetWorkingDirectoryAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Await conn.SetWorkingDirectory("/full/or/relative/path", token)
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetAbsoluteDir.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FluentFTP.Helpers;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class FtpClient {
9 |
10 | ///
11 | /// Ensure a relative dir is absolute by prepending the working dir
12 | ///
13 | protected string GetAbsoluteDir(string path) {
14 | string dirPath = null;
15 | if (ServerHandler != null && ServerHandler.IsCustomGetAbsoluteDir()) {
16 | dirPath = ServerHandler.GetAbsoluteDir(this, path);
17 | }
18 |
19 | if (dirPath != null) {
20 | return dirPath;
21 | }
22 |
23 | path = GetAbsolutePath(path);
24 |
25 | path = !path.EndsWith("/") ? path + "/" : path;
26 |
27 | return path;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpTraceLevel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Defines the level of the tracing message. Depending on the framework version this is translated
6 | /// to an equivalent logging level in System.Diagnostices (if available)
7 | ///
8 | public enum FtpTraceLevel {
9 | ///
10 | /// Used for logging Debug or Verbose level messages
11 | ///
12 | Verbose,
13 |
14 | ///
15 | /// Used for logging Informational messages
16 | ///
17 | Info,
18 |
19 | ///
20 | /// Used for logging non-fatal or ignorable error messages
21 | ///
22 | Warn,
23 |
24 | ///
25 | /// Used for logging Error messages that may need investigation
26 | ///
27 | Error
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/SetWorkingDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class SetWorkingDirectoryExample {
9 |
10 | public static void SetWorkingDirectory() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 |
13 | conn.Connect();
14 | conn.SetWorkingDirectory("/full/or/relative/path");
15 | }
16 | }
17 |
18 | public static async Task SetWorkingDirectoryAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 |
22 | await conn.Connect(token);
23 | await conn.SetWorkingDirectory("/full/or/relative/path", token);
24 | }
25 | }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/CreateDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module CreateDirectoryExample
9 | Sub CreateDirectory()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | conn.CreateDirectory("/test/path/that/should/be/created", True)
13 | End Using
14 | End Sub
15 |
16 | Async Function CreateDirectoryAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Await conn.CreateDirectory("/test/path/that/should/be/created", True, token)
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpResponseType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// The type of response the server responded with
6 | ///
7 | public enum FtpResponseType : int {
8 | ///
9 | /// No response
10 | ///
11 | None = 0,
12 |
13 | ///
14 | /// Success
15 | ///
16 | PositivePreliminary = 1,
17 |
18 | ///
19 | /// Success
20 | ///
21 | PositiveCompletion = 2,
22 |
23 | ///
24 | /// Success
25 | ///
26 | PositiveIntermediate = 3,
27 |
28 | ///
29 | /// Temporary failure
30 | ///
31 | TransientNegativeCompletion = 4,
32 |
33 | ///
34 | /// Permanent failure
35 | ///
36 | PermanentNegativeCompletion = 5
37 | }
38 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/CreateDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class CreateDirectoryExample {
9 |
10 | public static void CreateDirectory() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | conn.CreateDirectory("/test/path/that/should/be/created", true);
15 | }
16 | }
17 |
18 | public static async Task CreateDirectoryAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 | await conn.Connect(token);
22 |
23 | await conn.CreateDirectory("/test/path/that/should/be/created", true, token);
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpHashAlgorithm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Different types of hashing algorithms for computing checksums.
6 | ///
7 | [Flags]
8 | public enum FtpHashAlgorithm : int {
9 |
10 | ///
11 | /// Automatic algorithm, or hashing not supported.
12 | ///
13 | NONE = 0,
14 |
15 | ///
16 | /// SHA-1 algorithm
17 | ///
18 | SHA1 = 1,
19 |
20 | ///
21 | /// SHA-256 algorithm
22 | ///
23 | SHA256 = 2,
24 |
25 | ///
26 | /// SHA-512 algorithm
27 | ///
28 | SHA512 = 4,
29 |
30 | ///
31 | /// MD5 algorithm
32 | ///
33 | MD5 = 8,
34 |
35 | ///
36 | /// CRC algorithm
37 | ///
38 | CRC = 16
39 | }
40 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpObjectSubType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Type of file system of object
6 | ///
7 | public enum FtpObjectSubType {
8 |
9 | ///
10 | /// The default subtype.
11 | ///
12 | Unknown,
13 |
14 | ///
15 | /// A sub directory within the listed directory.
16 | /// (Only set when machine listing is available and type is 'dir')
17 | ///
18 | SubDirectory,
19 |
20 | ///
21 | /// The self directory.
22 | /// (Only set when machine listing is available and type is 'cdir')
23 | ///
24 | SelfDirectory,
25 |
26 | ///
27 | /// The parent directory.
28 | /// (Only set when machine listing is available and type is 'pdir')
29 | ///
30 | ParentDirectory,
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **FTP Server OS:** Unix / Windows / Embedded
2 |
3 | **FTP Server Type:** Vsftpd / glFTPd / BFTPd / ProFTPD / Pure-FTPd / IBM CS FTP (z/OS, OS/400) / Windows CE / Windows Server IIS / Vax / VMS / OpenVMS / Tandem / HP NonStop
4 |
5 | **Client Computer OS:** Windows / Ubuntu / Debian / Linux Mint / Arch Linux
6 |
7 | **FluentFTP Version:** ?
8 |
9 | **Framework:** .NET 2 / 3.5 / 4 / 5 / 6 / 7 / 8 / UWP / Xamarin / Mono
10 |
11 |
12 |
13 | **Logs :**
14 |
15 |
21 |
22 | ```
23 |
24 |
25 |
26 | ```
27 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/DisableUTF8.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 |
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Disables UTF8 support and changes the Encoding property
12 | /// back to ASCII. If the server returns an error when trying
13 | /// to turn UTF8 off a FtpCommandException will be thrown.
14 | ///
15 | public async Task DisableUTF8(CancellationToken token = default(CancellationToken)) {
16 | FtpReply reply;
17 |
18 | reply = await Execute("OPTS UTF8 OFF", token);
19 |
20 | if (!reply.Success) {
21 | throw new FtpCommandException(reply);
22 | }
23 |
24 | m_textEncoding = Encoding.ASCII;
25 | m_textEncodingAutoUTF = false;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpConnectionState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 |
5 | ///
6 | /// Actual connection state from the FTP client to the FTP server, as determined by the NOOP Deamon.
7 | ///
8 | public enum FtpConnectionState {
9 |
10 | ///
11 | /// Unknown state. NOOP Deamon will determine the state in a short while.
12 | ///
13 | Unknown,
14 |
15 | ///
16 | /// Not a good state and it will be brought down, closed and disposed soon.
17 | ///
18 | PendingDisconnect,
19 |
20 | ///
21 | /// Closed and disposed.
22 | ///
23 | Disconnected,
24 |
25 | ///
26 | /// Connected to the FTP server, at least the last time the NOOP daemon checked the connection.
27 | ///
28 | Connected,
29 |
30 | };
31 |
32 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/Handshake.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 | using System;
3 | using System.IO;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Called during . Typically extended by FTP proxies.
12 | ///
13 | protected virtual async Task HandshakeAsync(CancellationToken token = default(CancellationToken)) {
14 | FtpReply reply;
15 | if (!(reply = await GetReply(token)).Success) {
16 | if (reply.Code == null) {
17 | throw new IOException("The connection was terminated before a greeting could be read.");
18 | }
19 | else {
20 | throw new FtpCommandException(reply);
21 | }
22 | }
23 |
24 | HandshakeReply = reply;
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/GetWorkingDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module GetWorkingDirectoryExample
9 | Sub GetWorkingDirectory()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | Console.WriteLine("The working directory is: " & conn.GetWorkingDirectory())
13 | End Using
14 | End Sub
15 |
16 | Async Function GetWorkingDirectoryAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Console.WriteLine("The working directory is: " & Await conn.GetWorkingDirectory(token))
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpCompareResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 |
7 | ///
8 | /// The result of a file comparison operation.
9 | ///
10 | public enum FtpCompareResult {
11 |
12 | ///
13 | /// Success. Local and remote files are exactly equal.
14 | ///
15 | Equal = 1,
16 |
17 | ///
18 | /// Failure. Local and remote files do not match.
19 | ///
20 | NotEqual = 2,
21 |
22 | ///
23 | /// Failure. Either the local or remote file does not exist.
24 | ///
25 | FileNotExisting = 3,
26 |
27 | ///
28 | /// Failure. Checksum verification is enabled and your server does not support any hash algorithm.
29 | ///
30 | ChecksumNotSupported = 4,
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/GetFileSize.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module GetFileSizeExample
9 | Sub GetFileSize()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | Console.WriteLine("The file size is: " & conn.GetFileSize("/full/or/relative/path/to/file"))
13 | End Using
14 | End Sub
15 |
16 | Async Function GetFileSizeAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Console.WriteLine("The file size is: " & Await conn.GetFileSize("/full/or/relative/path/to/file", -1, token))
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/GetWorkingDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class GetWorkingDirectoryExample {
9 |
10 | public static void GetWorkingDirectory() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | Console.WriteLine("The working directory is: " + conn.GetWorkingDirectory());
15 | }
16 | }
17 |
18 | public static async Task GetWorkingDirectoryAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 | await conn.Connect(token);
22 |
23 | Console.WriteLine("The working directory is: " + await conn.GetWorkingDirectory(token));
24 | }
25 | }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetAbsoluteFilePath.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FluentFTP.Helpers;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Concat a path and a filename
12 | ///
13 | protected async Task GetAbsoluteFilePathAsync(string path, string fileName, CancellationToken token) {
14 | string filePath = null;
15 | if (ServerHandler != null && ServerHandler.IsCustomGetAbsoluteFilePath()) {
16 | filePath = await ServerHandler.GetAbsoluteFilePathAsync(this, path, fileName, token);
17 | }
18 |
19 | if (filePath != null) {
20 | return filePath;
21 | }
22 |
23 | path = !path.EndsWith("/") ? path + "/" + fileName : path + fileName;
24 |
25 | return path;
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/DirectoryExists.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class DirectoryExistsExample {
9 |
10 | public static void DirectoryExists() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | if (conn.DirectoryExists("/full/or/relative/path")) {
15 | // do something
16 | }
17 | }
18 | }
19 |
20 | public static async Task DirectoryExistsAsync() {
21 | var token = new CancellationToken();
22 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
23 | await conn.Connect(token);
24 |
25 | if (await conn.DirectoryExists("/full/or/relative/path", token)) {
26 | // do something
27 | }
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/ConnectFTPS.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module ConnectFTPSExample
9 | Sub ConnectFTPS()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit
12 | conn.Config.ValidateAnyCertificate = True
13 | conn.Connect()
14 | End Using
15 | End Sub
16 |
17 | Async Function ConnectFTPSAsync() As Task
18 | Dim token = New CancellationToken()
19 |
20 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
21 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit
22 | conn.Config.ValidateAnyCertificate = True
23 | Await conn.Connect(token)
24 | End Using
25 | End Function
26 | End Module
27 | End Namespace
28 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/FileExists.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module FileExistsExample
9 | Sub FileExists()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 |
13 | If conn.FileExists("/full/or/relative/path") Then
14 | ' do something
15 | End If
16 |
17 | End Using
18 | End Sub
19 |
20 | Async Function FileExistsAsync() As Task
21 | Dim token = New CancellationToken()
22 |
23 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
24 | Await conn.Connect(token)
25 |
26 | If Await conn.FileExists("/full/or/relative/path", token) Then
27 | ' do something
28 | End If
29 |
30 | End Using
31 | End Function
32 | End Module
33 | End Namespace
34 |
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpListParseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 | ///
8 | /// Exception thrown by FtpListParser when parsing of FTP directory listing fails.
9 | ///
10 | #if NETFRAMEWORK
11 | [Serializable]
12 | #endif
13 | public class FtpListParseException : FtpException {
14 | ///
15 | /// Creates a new FtpListParseException.
16 | ///
17 | public FtpListParseException()
18 | : base("Cannot parse file listing!") {
19 | }
20 |
21 | #if NETFRAMEWORK
22 | ///
23 | /// Must be implemented so every Serializer can Deserialize the Exception
24 | ///
25 | protected FtpListParseException(SerializationInfo info, StreamingContext context) : base(info, context) {
26 | }
27 |
28 | #endif
29 | }
30 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/GetFileSize.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class GetFileSizeExample {
9 |
10 | public static void GetFileSize() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | Console.WriteLine("The file size is: " + conn.GetFileSize("/full/or/relative/path/to/file"));
15 | }
16 | }
17 |
18 | public static async Task GetFileSizeAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 | await conn.Connect(token);
22 |
23 | Console.WriteLine("The file size is: " + await conn.GetFileSize("/full/or/relative/path/to/file", -1, token));
24 | }
25 | }
26 |
27 |
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpZOSListRealm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Flags that can control how a file listing is performed. If you are unsure what to use, set it to Auto.
6 | ///
7 | [Flags]
8 | public enum FtpZOSListRealm {
9 | ///
10 | /// Not z/OS Server
11 | ///
12 | Invalid = -1,
13 |
14 | ///
15 | /// HFS / USS
16 | ///
17 | Unix = 0,
18 |
19 | ///
20 | /// z/OS classic dataset
21 | ///
22 | Dataset = 1,
23 |
24 | ///
25 | /// Partitioned dataset member, RECFM != U
26 | ///
27 | Member = 2,
28 |
29 | ///
30 | /// Partitioned dataset member, RECFM = U
31 | ///
32 | MemberU = 3,
33 |
34 | ///
35 | /// SITE FILETYPE=JES LIST
36 | ///
37 | Jes2 = 4
38 | }
39 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/ConnectFTPS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class ConnectFTPSExample {
9 |
10 | public static void ConnectFTPS() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit;
13 | conn.Config.ValidateAnyCertificate = true;
14 | conn.Connect();
15 | }
16 | }
17 |
18 | public static async Task ConnectFTPSAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 |
22 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit;
23 | conn.Config.ValidateAnyCertificate = true;
24 | await conn.Connect(token);
25 | }
26 | }
27 |
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/GetModifiedTime.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module GetModifiedTimeExample
9 | Sub GetModifiedTime()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 | Console.WriteLine("The modified type is: " & conn.GetModifiedTime("/full/or/relative/path/to/file"))
13 | End Using
14 | End Sub
15 |
16 | Async Function GetModifiedTimeAsync() As Task
17 | Dim token = New CancellationToken()
18 |
19 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
20 | Await conn.Connect(token)
21 | Console.WriteLine("The modified type is: " & Await conn.GetModifiedTime("/full/or/relative/path/to/file", token))
22 | End Using
23 | End Function
24 | End Module
25 | End Namespace
26 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetAbsoluteDir.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FluentFTP.Helpers;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Ensure a relative dir is absolute by prepending the working dir
12 | ///
13 | protected async Task GetAbsoluteDirAsync(string path, CancellationToken token) {
14 | string dirPath = null;
15 | if (ServerHandler != null && ServerHandler.IsCustomGetAbsoluteDir()) {
16 | dirPath = await ServerHandler.GetAbsoluteDirAsync(this, path, token);
17 | }
18 |
19 | if (dirPath != null) {
20 | return dirPath;
21 | }
22 |
23 | path = await GetAbsolutePathAsync(path, token);
24 |
25 | path = !path.EndsWith("/") ? path + "/" : path;
26 |
27 | return path;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DirectoryExists.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module DirectoryExistsExample
9 | Sub DirectoryExists()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 |
13 | If conn.DirectoryExists("/full/or/relative/path") Then
14 | ' do something
15 | End If
16 |
17 | End Using
18 | End Sub
19 |
20 | Async Function DirectoryExistsAsync() As Task
21 | Dim token = New CancellationToken()
22 |
23 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
24 | Await conn.Connect(token)
25 |
26 | If Await conn.DirectoryExists("/full/or/relative/path") Then
27 | ' do something
28 | End If
29 |
30 | End Using
31 | End Function
32 | End Module
33 | End Namespace
34 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetReply.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using System.Diagnostics;
5 | using FluentFTP.Client.Modules;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Retrieves a reply from the server.
12 | /// Support "normal" mode waiting for a command reply, subject to timeout exception
13 | /// and "exhaustNoop" mode, which waits for 10 seconds to collect out of band NOOP responses
14 | ///
15 | /// The token that can be used to cancel the entire process.
16 | /// FtpReply representing the response from the server
17 | public async Task GetReply(CancellationToken token = default(CancellationToken)) {
18 | return await ((IInternalFtpClient)this).GetReplyInternal(token, null, false, 0);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpDate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Controls how timestamps returned by the server are converted.
6 | ///
7 | public enum FtpDate {
8 |
9 | ///
10 | /// Returns the server timestamps in Server Time. No timezone conversion is performed.
11 | ///
12 | ServerTime = 0,
13 |
14 | ///
15 | /// Returns the server timestamps in Local Time.
16 | /// Ensure that the `ServerTimeZone` property is set to the server's timezone.
17 | /// Ensure that the `ClientTimeZone` property is set to the client's timezone.
18 | ///
19 | LocalTime = 1,
20 |
21 | ///
22 | /// Returns the server timestamps in UTC (Coordinated Universal Time).
23 | /// Ensure that the `ServerTimeZone` property is correctly set to the server's timezone.
24 | ///
25 | UTC = 2,
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/DeleteFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentFTP.Helpers;
3 | using System.Threading;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading.Tasks;
6 | using FluentFTP.Exceptions;
7 |
8 | namespace FluentFTP {
9 | public partial class FtpClient {
10 |
11 | ///
12 | /// Deletes a file on the server
13 | ///
14 | /// The full or relative path to the file
15 | public void DeleteFile(string path) {
16 | FtpReply reply;
17 |
18 | // verify args
19 | if (path.IsBlank()) {
20 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
21 | }
22 |
23 | path = path.GetFtpPath();
24 |
25 | LogFunction(nameof(DeleteFile), new object[] { path });
26 |
27 | if (!(reply = Execute("DELE " + path)).Success) {
28 | throw new FtpCommandException(reply);
29 | }
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/DeleteDirectory.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP;
5 |
6 | namespace Examples {
7 | internal static class DeleteDirectoryExample {
8 |
9 | public static void DeleteDirectory() {
10 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
11 | conn.Connect();
12 |
13 | // Remove the directory and all files and subdirectories inside it
14 | conn.DeleteDirectory("/path/to/directory");
15 | }
16 | }
17 |
18 | public static async Task DeleteDirectoryAsync() {
19 | var token = new CancellationToken();
20 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
21 | await conn.Connect(token);
22 |
23 | // Remove the directory and all files and subdirectories inside it
24 | await conn.DeleteDirectory("/path/to/directory", token);
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/GetModifiedTime.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class GetModifiedTimeExample {
9 |
10 | public static void GetModifiedTime() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | Console.WriteLine("The modified type is: " +
15 | conn.GetModifiedTime("/full/or/relative/path/to/file"));
16 | }
17 | }
18 |
19 | public static async Task GetModifiedTimeAsync() {
20 | var token = new CancellationToken();
21 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
22 | await conn.Connect(token);
23 |
24 | Console.WriteLine("The modified type is: " +
25 | await conn.GetModifiedTime("/full/or/relative/path/to/file", token));
26 | }
27 | }
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DeleteDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System.Net
2 | Imports System.Threading
3 | Imports System.Threading.Tasks
4 | Imports FluentFTP
5 |
6 | Namespace Examples
7 | Friend Module DeleteDirectoryExample
8 | Sub DeleteDirectory()
9 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
10 | conn.Connect()
11 |
12 | ' Remove the directory And all files And subdirectories inside it
13 | conn.DeleteDirectory("/path/to/directory")
14 |
15 | End Using
16 | End Sub
17 |
18 | Async Function DeleteDirectoryAsync() As Task
19 | Dim token = New CancellationToken()
20 |
21 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
22 | Await conn.Connect(token)
23 |
24 | ' Remove the directory And all files And subdirectories inside it
25 | Await conn.DeleteDirectory("/path/to/directory", token)
26 |
27 | End Using
28 | End Function
29 | End Module
30 | End Namespace
31 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/Connect.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Client.BaseClient {
5 |
6 | public partial class BaseFtpClient {
7 |
8 | ///
9 | /// Connect to the server
10 | ///
11 | /// true indicates that we want a reconnect to take place.
12 | void IInternalFtpClient.ConnectInternal(bool reConnect) {
13 | ((IFtpClient)this).Connect(reConnect);
14 | }
15 |
16 | ///
17 | /// Connect to the server
18 | ///
19 | /// true indicates that we want a reconnect to take place.
20 | /// The token that can be used to cancel the entire process
21 | async Task IInternalFtpClient.ConnectInternal(bool reConnect, CancellationToken token) {
22 | await ((IAsyncFtpClient)this).Connect(reConnect, token);
23 | }
24 |
25 | }
26 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpOperatingSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Defines the operating system of the FTP server.
6 | ///
7 | public enum FtpOperatingSystem {
8 | ///
9 | /// Unknown operating system
10 | ///
11 | Unknown,
12 |
13 | ///
14 | /// Definitely Windows or Windows Server
15 | ///
16 | Windows,
17 |
18 | ///
19 | /// Definitely Unix or AIX-based server
20 | ///
21 | Unix,
22 |
23 | ///
24 | /// Definitely VMS or OpenVMS server
25 | ///
26 | VMS,
27 |
28 | ///
29 | /// Definitely IBM OS/400 server
30 | ///
31 | IBMOS400,
32 |
33 | ///
34 | /// Definitely IBM z/OS server
35 | ///
36 | IBMzOS,
37 |
38 | ///
39 | /// Definitely SUN OS/Solaris server
40 | ///
41 | SunOS,
42 | }
43 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/Internal/SkippableFactDiscoverer.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Xunit.Internal;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Xunit.Abstractions;
8 | using Xunit.Sdk;
9 |
10 | namespace FluentFTP.Xunit.Attributes.Internal {
11 | internal class SkippableFactDiscoverer : IXunitTestCaseDiscoverer {
12 | readonly IMessageSink diagnosticMessageSink;
13 |
14 | public SkippableFactDiscoverer(IMessageSink diagnosticMessageSink) {
15 | this.diagnosticMessageSink = diagnosticMessageSink;
16 | }
17 |
18 | public IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) {
19 | yield return new SkippableFactTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/DLinkServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | namespace FluentFTP.Servers.Handlers {
4 |
5 | ///
6 | /// Server-specific handling for D-Link FTP servers
7 | ///
8 | internal class DLinkServer : FtpBaseServer {
9 |
10 | ///
11 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
12 | ///
13 | public override FtpServer ToEnum() {
14 | return FtpServer.DLink;
15 | }
16 |
17 | ///
18 | /// Return true if your server is detected by the given FTP server welcome message.
19 | ///
20 | public override bool DetectByWelcome(string message) {
21 |
22 | // Detect D-Link server
23 | // Welcome message: "220 D-Link FTP version 1.0 ready"
24 | if (message.Contains("D-Link FTP")) {
25 | return true;
26 | }
27 |
28 | return false;
29 | }
30 |
31 | }
32 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/SetWorkingDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using FluentFTP.Exceptions;
8 |
9 | namespace FluentFTP {
10 | public partial class FtpClient {
11 |
12 | ///
13 | /// Sets the work directory on the server
14 | ///
15 | /// The path of the directory to change to
16 | public void SetWorkingDirectory(string path) {
17 |
18 | path = path.GetFtpPath();
19 |
20 | LogFunction(nameof(SetWorkingDirectory), new object[] { path });
21 |
22 | FtpReply reply;
23 |
24 | // exit if invalid path
25 | if (path is "." or "./") {
26 | return;
27 | }
28 |
29 | // modify working dir
30 | if (!(reply = Execute("CWD " + path)).Success) {
31 | throw new FtpCommandException(reply);
32 | }
33 |
34 | }
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/TPLinkServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for TP-LINK FTP servers
8 | ///
9 | internal class TPLinkServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.TPLink;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect TP-LINK server
24 | // Welcome message: "TP-LINK FTP version 1.0 ready"
25 | if (message.Contains("TP-LINK FTP")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpVerifyMethod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Defines which verification types should be performed when
6 | /// uploading/downloading files using the high-level APIs.
7 | /// Multiple verification types can be combined.
8 | ///
9 | [Flags]
10 | public enum FtpVerifyMethod {
11 | ///
12 | /// Compares the file size.
13 | /// Both file sizes should exactly match for the file to be considered equal.
14 | ///
15 | Size = 1,
16 |
17 | ///
18 | /// Compares the date modified of the file.
19 | /// Both dates should exactly match for the file to be considered equal.
20 | ///
21 | Date = 2,
22 |
23 | ///
24 | /// Compares the checksum or hash of the file using the first supported hash algorithm.
25 | /// Both checksums should exactly match for the file to be considered equal.
26 | ///
27 | Checksum = 4,
28 | }
29 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/BFtpdServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for BFTPd FTP servers
8 | ///
9 | internal class BFtpdServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.BFTPd;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect BFTPd server
24 | // Welcome message: "220 bftpd 2.2.1 at 192.168.1.1 ready"
25 | if (message.Contains("bftpd ")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/WSFTPServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for WS_FTP servers
8 | ///
9 | internal class WSFTPServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.WSFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect FTP2S3 server
24 | // Welcome message: "220 ***.com X2 WS_FTP Server 8.5.0(24135676)"
25 | if (message.Contains("WS_FTP Server")) {
26 | return true;
27 | }
28 | return false;
29 | }
30 |
31 | }
32 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/PyFtpdLibServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for PyFtpdLib FTP servers
8 | ///
9 | internal class PyFtpdLibServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.PyFtpdLib;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect PyFtpdLib server
24 | // Welcome message: "220 pyftpdlib 1.5.6 ready"
25 | if (message.Contains("pyftpdlib ")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/CrushFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for CrushFTP servers
8 | ///
9 | internal class CrushFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.CrushFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect CrushFTP server
24 | // Welcome message: "220 CrushFTP Server Ready!"
25 | if (message.Contains("CrushFTP Server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/IDALFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for ABB IDAL FTP servers
8 | ///
9 | internal class IDALFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.IDALFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect IDAL server
24 | // Welcome message: "220 Welcome to IDAL FTP server. READY."
25 | if (message.Contains("IDAL FTP server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/Disconnect.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | public partial class FtpClient {
5 |
6 | ///
7 | /// Disconnects from the server
8 | ///
9 | public void Disconnect() {
10 | LogFunction(nameof(Disconnect), null);
11 |
12 | if (IsConnected) {
13 | try {
14 | if (Config.DisconnectWithQuit) {
15 | Execute("QUIT");
16 | }
17 | }
18 | catch (Exception ex) {
19 | LogWithPrefix(FtpTraceLevel.Verbose, "FtpClient.Disconnect().Execute(\"QUIT\"): " + ex.Message);
20 | }
21 | finally {
22 | // When debugging, the stream might have already been taken down
23 | // from the remote side, thus causing an exception here, so check for null
24 | if (m_stream != null) {
25 | m_stream.Close();
26 | }
27 | }
28 | }
29 | else {
30 | LogWithPrefix(FtpTraceLevel.Verbose, "Connection already closed, nothing to do.");
31 | }
32 | }
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/TitanFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for Titan FTP servers
8 | ///
9 | internal class TitanFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.TitanFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Pure-FTPd server
24 | // Welcome message: "220 Titan FTP Server 10.01.1740 Ready"
25 | if (message.Contains("Titan FTP")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/XLightServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for XLight FTP servers
8 | ///
9 | internal class XLightServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.XLight;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect XLight server
24 | // Welcome message: "220 Xlight FTP Server 3.9 ready"
25 | if (message.Contains("Xlight FTP Server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetChmod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP {
7 | public partial class AsyncFtpClient {
8 |
9 | ///
10 | /// Retrieve the permissions of the given file/folder as an integer in the CHMOD format.
11 | /// Throws FtpCommandException if there is an issue.
12 | /// Returns 0 if the server did not specify a permission value.
13 | /// Use `GetFilePermissions` if you required the permissions in the FtpPermission format.
14 | ///
15 | /// The full or relative path to the item
16 | /// The token that can be used to cancel the entire process
17 | public async Task GetChmod(string path, CancellationToken token = default(CancellationToken)) {
18 | FtpListItem item = await GetFilePermissions(path, token);
19 | return item != null ? item.Chmod : 0;
20 | }
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/ValidateAutoDetect.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 | using System;
3 |
4 | namespace FluentFTP.Client.BaseClient {
5 | public partial class BaseFtpClient {
6 |
7 | ///
8 | /// Validate the client before the auto detect process
9 | ///
10 | ///
11 | ///
12 | protected void ValidateAutoDetect() {
13 | if (IsDisposed) {
14 | throw new ObjectDisposedException("This FtpClient object has been disposed. It is no longer accessible.");
15 | }
16 |
17 | if (Host == null) {
18 | throw new FtpException("No host has been specified. Please set the 'Host' property before trying to auto connect.");
19 | }
20 |
21 | if (Credentials == null) {
22 | throw new FtpException("No username and password has been specified. Please set the 'Credentials' property before trying to auto connect.");
23 | }
24 | }
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/IsRoot.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace FluentFTP {
9 | public partial class FtpClient {
10 |
11 | ///
12 | /// Is the current working directory the root?
13 | ///
14 | /// true if root.
15 | public bool IsRoot() {
16 |
17 | // this case occurs immediately after connection and after the working dir has changed
18 | if (Status.LastWorkingDir == null) {
19 | ReadCurrentWorkingDirectory();
20 | }
21 |
22 | if (Status.LastWorkingDir.IsFtpRootDirectory()) {
23 | return true;
24 | }
25 |
26 | // execute server-specific check if the current working dir is a root directory
27 | if (ServerHandler != null && ServerHandler.IsRoot(this, Status.LastWorkingDir)) {
28 | return true;
29 | }
30 |
31 | return false;
32 | }
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/CerberusServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for Cerberus FTP servers
8 | ///
9 | internal class CerberusServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.Cerberus;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Cerberus server
24 | // Welcome message: "220-Cerberus FTP Server Personal Edition"
25 | if (message.Contains("Cerberus FTP")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/HomegateFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for HomegateFTP servers
8 | ///
9 | internal class HomegateFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.HomegateFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Homegate FTP server
24 | // Welcome message: "220 Homegate FTP Server ready"
25 | if (message.Contains("Homegate FTP Server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/Log_Serilog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using FluentFTP;
4 | using FluentFTP.Logging;
5 | using Serilog;
6 | using Serilog.Extensions.Logging;
7 |
8 | namespace Examples {
9 | internal static class SerilogExample {
10 |
11 | public static void Configure() {
12 |
13 | using (var conn = new FtpClient()) {
14 | conn.Host = "localhost";
15 | conn.Credentials = new NetworkCredential("ftptest", "ftptest");
16 |
17 |
18 | // create Serilog logger
19 | var serilogLogger = new LoggerConfiguration()
20 | .MinimumLevel.Debug()
21 | .WriteTo.File("logs/FluentFTPLogs.txt", rollingInterval: RollingInterval.Day)
22 | .CreateLogger();
23 |
24 | // wrap with MELA ILogger
25 | var microsoftLogger = new SerilogLoggerFactory(serilogLogger)
26 | .CreateLogger("FTP");
27 |
28 | // wrap with FtpLogAdapter
29 | conn.Logger = new FtpLogAdapter(microsoftLogger);
30 |
31 |
32 | conn.Connect();
33 | }
34 | }
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/Ftp2S3GatewayServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for FTP2S3Gateway FTP servers
8 | ///
9 | internal class Ftp2S3GatewayServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.FTP2S3Gateway;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect FTP2S3 server
24 | // Welcome message: "220 Aruba FTP2S3 gateway 1.0.1 ready"
25 | if (message.Contains("FTP2S3 gateway")) {
26 | return true;
27 | }
28 | return false;
29 | }
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/CSharpExamples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | Library
6 | latest
7 |
8 |
9 | AnyCPU;x64
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/GlobalScapeEftServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for GlobalScapeEFT FTP servers
8 | ///
9 | internal class GlobalScapeEftServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.GlobalScapeEFT;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect GlobalScape EFT server
24 | // Welcome message: "EFT Server Enterprise 7.4.5.6"
25 | if (message.Contains("EFT Server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP.Logging/FtpLogAdapter.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP;
2 | using Microsoft.Extensions.Logging;
3 |
4 | namespace FluentFTP.Logging {
5 | ///
6 | /// Logging adapter to help FluentFTP integrate with MELA-compatible Loggers (NLog, Serilog, Log4Net, PLogger, etc).
7 | /// Read the Logging page: https://github.com/robinrodricks/FluentFTP/wiki/Logging
8 | ///
9 | public sealed class FtpLogAdapter : IFtpLogger {
10 | private readonly ILogger adaptee;
11 |
12 | public FtpLogAdapter(ILogger adaptee) =>
13 | this.adaptee = adaptee;
14 |
15 | public void Log(FtpLogEntry entry) =>
16 | adaptee.Log(ToLevel(entry.Severity), 0, entry.Message, entry.Exception, (s, _) => s);
17 |
18 | private static LogLevel ToLevel(FtpTraceLevel s) => s switch {
19 | FtpTraceLevel.Verbose => LogLevel.Debug,
20 | FtpTraceLevel.Info => LogLevel.Information,
21 | FtpTraceLevel.Warn => LogLevel.Warning,
22 | FtpTraceLevel.Error => LogLevel.Error,
23 | _ => LogLevel.Information
24 | };
25 | }
26 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/ExecuteFTPCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 | using FluentFTP.Exceptions;
7 |
8 | namespace Examples {
9 | internal static class ExecuteFTPCommandExample {
10 |
11 | public static void Execute() {
12 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
13 | conn.Connect();
14 |
15 | FtpReply reply;
16 | if (!(reply = conn.Execute("SITE CHMOD 640 FOO.TXT")).Success) {
17 | throw new FtpCommandException(reply);
18 | }
19 | }
20 | }
21 |
22 | public static async Task ExecuteAsync() {
23 | var token = new CancellationToken();
24 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
25 | await conn.Connect(token);
26 |
27 | FtpReply reply;
28 | if (!(reply = await conn.Execute("SITE CHMOD 640 FOO.TXT", token)).Success) {
29 | throw new FtpCommandException(reply);
30 | }
31 | }
32 | }
33 |
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/FluentFTP/Helpers/TimeSpans.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP.Helpers {
8 | ///
9 | /// Extension methods related to FTP time span values
10 | ///
11 | public static class TimeSpans {
12 |
13 | public static string ToShortString(this TimeSpan span, string format = "0.###", string zeroString = "<1ms") {
14 | if (span.TotalDays > 1) {
15 | return span.TotalDays.ToString(format) + "d";
16 | }
17 | if (span.TotalHours > 1) {
18 | return span.TotalHours.ToString(format) + "h";
19 | }
20 | if (span.TotalMinutes > 1) {
21 | return span.TotalMinutes.ToString(format) + "m";
22 | }
23 | if (span.TotalSeconds > 1) {
24 | return span.TotalSeconds.ToString(format) + "s";
25 | }
26 | if (span.TotalMilliseconds > 1) {
27 | return ((int)span.TotalMilliseconds).ToString() + "ms";
28 | }
29 | return zeroString;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/RumpusServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for Rumpus FTP servers
8 | ///
9 | internal class RumpusServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.Rumpus;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Rumpus server
24 | // Welcome message: "Response: 220-Welcome To Rumpus!"
25 | // "Response: 220 Service ready for new user"
26 | if (message.Contains("Welcome To Rumpus")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | }
34 | }
--------------------------------------------------------------------------------
/FluentFTP/Helpers/Logging/LoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentFTP.Helpers.Logging;
3 |
4 | namespace FluentFTP.Helpers.Logging {
5 | internal static class LoggerExtensions {
6 |
7 | ///
8 | /// Log a message to the given IFluentLogger class.
9 | ///
10 | public static void Log(this IFtpLogger logger, FtpTraceLevel eventType, string message, Exception ex = null) {
11 | logger.Log(new FtpLogEntry(eventType, message, ex));
12 | }
13 |
14 | ///
15 | /// Get the log prefix for the given trace level type.
16 | ///
17 | public static string GetLogPrefix(this FtpTraceLevel eventType) {
18 | switch (eventType) {
19 | case FtpTraceLevel.Verbose:
20 | return "Status: ";
21 |
22 | case FtpTraceLevel.Info:
23 | return "Status: ";
24 |
25 | case FtpTraceLevel.Warn:
26 | return "Warning: ";
27 |
28 | case FtpTraceLevel.Error:
29 | return "Error: ";
30 | }
31 |
32 | return "Status: ";
33 | }
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/Noop.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Net.Sockets;
4 | using System.Text.RegularExpressions;
5 | using System.Linq;
6 | using System.Net;
7 | using FluentFTP.Helpers;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace FluentFTP {
12 | public partial class FtpClient {
13 |
14 | ///
15 | /// Sends the NOOP command according to (effectively a no-op if 0).
16 | /// Please call as needed to read the "OK" command sent by the server and prevent stale data on the socket.
17 | /// Note that response is not guaranteed by all FTP servers when sent during file transfers.
18 | /// Send the command regardless of NoopInterval
19 | ///
20 | /// true if NOOP command was sent
21 | public bool Noop(bool ignoreNoopInterval = false) {
22 | return ((IInternalFtpClient)this).NoopInternal(ignoreNoopInterval);
23 | }
24 |
25 | }
26 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/FritzBoxServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for FritzBox FTP servers
8 | ///
9 | internal class FritzBoxServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.FritzBox;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect FTP2S3 server
24 | // Welcome message: "220 FRITZ!Box7490 FTP server ready"
25 | // Welcome message: "220 FRITZ!BoxFonWLAN7390 FTP server ready"
26 | if (message.Contains("FRITZ!Box")) {
27 | return true;
28 | }
29 | return false;
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpMissingSocketException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 | ///
8 | /// Exception is thrown by FtpSocketStream when there is no FTP server socket to connect to.
9 | ///
10 | #if NETFRAMEWORK
11 | [Serializable]
12 | #endif
13 | public class FtpMissingSocketException : FtpException {
14 | ///
15 | /// Creates a new FtpMissingSocketException.
16 | ///
17 | /// The original exception.
18 | public FtpMissingSocketException(Exception innerException)
19 | : base("Socket is missing", innerException) {
20 | }
21 |
22 | #if NETFRAMEWORK
23 | ///
24 | /// Must be implemented so every Serializer can Deserialize the Exception
25 | ///
26 | protected FtpMissingSocketException(SerializationInfo info, StreamingContext context) : base(info, context) {
27 | }
28 |
29 | #endif
30 | }
31 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/GlFtpdServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for glFTPd FTP servers
8 | ///
9 | internal class GlFtpdServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.glFTPd;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect glFTPd server
24 | // Welcome message: "220 W 00 T (glFTPd 2.01 Linux+TLS) ready."
25 | // Welcome message: "220 (glFTPd 2.01 Linux+TLS) ready."
26 | if (message.Contains("glFTPd ")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FluentFTP/Rules/FtpRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP.Rules {
6 |
7 | ///
8 | /// Base class used for all FTP Rules. Extend this class to create custom rules.
9 | /// You only need to provide an implementation for IsAllowed, and add any custom arguments that you require.
10 | ///
11 | public class FtpRule {
12 |
13 | ///
14 | /// Rule object
15 | ///
16 | public FtpRule() {
17 | }
18 |
19 | ///
20 | /// Returns true if the object has passed this rules.
21 | ///
22 | public virtual bool IsAllowed(FtpListItem result) {
23 | return true;
24 | }
25 |
26 | ///
27 | /// Returns true if the object has passed all the rules.
28 | ///
29 | public static bool IsAllAllowed(List rules, FtpListItem result) {
30 | foreach (var rule in rules) {
31 | if (!rule.IsAllowed(result)) {
32 | return false;
33 | }
34 | }
35 | return true;
36 | }
37 |
38 | }
39 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/ApacheFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for Apache (MINA) FTP servers
8 | ///
9 | internal class ApacheFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.Apache;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given SYST response message.
20 | /// Its a fallback method if the server did not send an identifying welcome message.
21 | ///
22 | public override bool DetectBySyst(string message) {
23 |
24 | // Detect Apache server
25 | // SYST type: "UNIX Type: Apache FtpServer"
26 | if (message.Contains("Apache FtpServer")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/SolarisFtpServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for SolarisFTP servers
8 | ///
9 | internal class SolarisFtpServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.SolarisFTP;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given SYST response message.
20 | /// Its a fallback method if the server did not send an identifying welcome message.
21 | ///
22 | public override bool DetectBySyst(string message) {
23 |
24 | // Detect SolarisFTP server
25 | // SYST response: "215 UNIX Type: L8 Version: SUNOS"
26 | if (message.Contains("SUNOS")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/IsRoot.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace FluentFTP {
9 | public partial class AsyncFtpClient {
10 |
11 | ///
12 | /// Is the current working directory the root?
13 | ///
14 | /// true if root.
15 | public async Task IsRoot(CancellationToken token = default(CancellationToken)) {
16 |
17 | // this case occurs immediately after connection and after the working dir has changed
18 | if (Status.LastWorkingDir == null) {
19 | await ReadCurrentWorkingDirectory(token);
20 | }
21 |
22 | if (Status.LastWorkingDir.IsFtpRootDirectory()) {
23 | return true;
24 | }
25 |
26 | // execute server-specific check if the current working dir is a root directory
27 | if (ServerHandler != null && ServerHandler.IsRoot(this, Status.LastWorkingDir)) {
28 | return true;
29 | }
30 |
31 | return false;
32 | }
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/MicroTikServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for MikroTik RouterOS FTP servers
8 | ///
9 | internal class MicroTikServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.MikroTik;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect MikroTik server
24 | // Welcome message: "MikroTik FTP server (MikroTik 2.9.27) ready"
25 | // Welcome message: "MikroTik FTP server (MikroTik 6.0rc2) ready"
26 | if (message.Contains("MikroTik FTP")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | }
34 | }
--------------------------------------------------------------------------------
/FluentFTP.Tests/Unit/IsProxyTests.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.BaseClient;
2 | using FluentFTP.Proxy.AsyncProxy;
3 | using FluentFTP.Proxy.SyncProxy;
4 | using Xunit;
5 |
6 | namespace FluentFTP.Tests.Unit {
7 | public class IsProxyTests {
8 | [MemberData(nameof(ProxyFtpClients))]
9 | [Theory]
10 | public void Proxy_clients_are_proxies(BaseFtpClient ftpClient) {
11 | // Act
12 | var isProxy = ftpClient.IsProxy();
13 |
14 | // Assert
15 | Assert.True(isProxy);
16 | }
17 |
18 | public static TheoryData ProxyFtpClients => new() {
19 | new AsyncFtpClientSocks4aProxy(new FtpProxyProfile()),
20 | new FtpClientSocks4aProxy(new FtpProxyProfile())
21 | };
22 |
23 | [MemberData(nameof(FtpClients))]
24 | [Theory]
25 | public void Clients_are_not_proxies(BaseFtpClient ftpClient) {
26 | // Act
27 | var isProxy = ftpClient.IsProxy();
28 |
29 | // Assert
30 | Assert.False(isProxy);
31 | }
32 |
33 | public static TheoryData FtpClients => new() {
34 | new AsyncFtpClient(),
35 | new FtpClient()
36 | };
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetFilePermissions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP {
7 | public partial class FtpClient {
8 |
9 | ///
10 | /// Retrieve the permissions of the given file/folder as an FtpListItem object with all "Permission" properties set.
11 | /// Throws FtpCommandException if there is an issue.
12 | /// Returns null if the server did not specify a permission value.
13 | /// Use `GetChmod` if you required the integer value instead.
14 | ///
15 | /// The full or relative path to the item
16 | public FtpListItem GetFilePermissions(string path) {
17 | // verify args
18 | if (path.IsBlank()) {
19 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
20 | }
21 |
22 | path = path.GetFtpPath();
23 |
24 | LogFunction(nameof(GetFilePermissions), new object[] { path });
25 |
26 | var result = GetObjectInfo(path);
27 |
28 | return result;
29 | }
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Robin Rodricks and FluentFTP Contributors
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/Client/AsyncClient/DeleteFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentFTP.Helpers;
3 | using System.Threading;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading.Tasks;
6 | using FluentFTP.Exceptions;
7 |
8 | namespace FluentFTP {
9 | public partial class AsyncFtpClient {
10 |
11 | ///
12 | /// Deletes a file from the server asynchronously
13 | ///
14 | /// The full or relative path to the file
15 | /// The token that can be used to cancel the entire process
16 | public async Task DeleteFile(string path, CancellationToken token = default(CancellationToken)) {
17 | FtpReply reply;
18 |
19 | // verify args
20 | if (path.IsBlank()) {
21 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
22 | }
23 |
24 | path = path.GetFtpPath();
25 |
26 | LogFunction(nameof(DeleteFile), new object[] { path });
27 |
28 | if (!(reply = await Execute("DELE " + path, token)).Success) {
29 | throw new FtpCommandException(reply);
30 | }
31 | }
32 |
33 | }
34 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/Rename.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module RenameExample
9 | Sub Rename()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 |
13 | ' renaming a directory Is dependent on the server! if you attempt it
14 | ' And it fails it's not because FluentFTP has a bug!
15 | conn.Rename("/full/or/relative/path/to/src", "/full/or/relative/path/to/dest")
16 | End Using
17 | End Sub
18 |
19 | Async Function RenameAsync() As Task
20 | Dim token = New CancellationToken()
21 |
22 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
23 | Await conn.Connect(token)
24 |
25 | ' renaming a directory Is dependent on the server! if you attempt it
26 | ' And it fails it's not because FluentFTP has a bug!
27 | Await conn.Rename("/full/or/relative/path/to/src", "/full/or/relative/path/to/dest", token)
28 | End Using
29 | End Function
30 | End Module
31 | End Namespace
32 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/FileExists.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class FileExistsExample {
9 |
10 | public static void FileExists() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | // The last parameter forces FluentFTP to use LIST -a
15 | // for getting a list of objects in the parent directory.
16 | if (conn.FileExists("/full/or/relative/path")) {
17 | // dome something
18 | }
19 | }
20 | }
21 |
22 | public static async Task FileExistsAsync() {
23 | var token = new CancellationToken();
24 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
25 | await conn.Connect(token);
26 |
27 | // The last parameter forces FluentFTP to use LIST -a
28 | // for getting a list of objects in the parent directory.
29 | if (await conn.FileExists("/full/or/relative/path", token)) {
30 | // dome something
31 | }
32 | }
33 | }
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/Rename.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 |
9 | internal static class RenameExample {
10 |
11 | public static void Rename() {
12 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
13 | conn.Connect();
14 |
15 | // renaming a directory is dependent on the server! if you attempt it
16 | // and it fails it's not because FluentFTP has a bug!
17 | conn.Rename("/full/or/relative/path/to/src", "/full/or/relative/path/to/dest");
18 | }
19 | }
20 |
21 | public static async Task RenameAsync() {
22 | var token = new CancellationToken();
23 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
24 | await conn.Connect(token);
25 |
26 | // renaming a directory is dependent on the server! if you attempt it
27 | // and it fails it's not because FluentFTP has a bug!
28 | await conn.Rename("/full/or/relative/path/to/src", "/full/or/relative/path/to/dest", token);
29 | }
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpLocalExists.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FluentFTP {
4 | ///
5 | /// Determines how we handle partially downloaded files
6 | ///
7 | public enum FtpLocalExists {
8 | ///
9 | /// Restart the download of a file if it is partially downloaded.
10 | /// Overwrites the file if it exists on disk.
11 | ///
12 | Overwrite,
13 |
14 | ///
15 | /// Resume the download of a file if it is partially downloaded.
16 | /// Appends to the file if it exists, by checking the length and adding the missing data.
17 | /// If the file doesn't exist on disk, a new file is created.
18 | ///
19 | Resume,
20 |
21 | ///
22 | /// Blindly skip downloading the file if it exists on disk, without any more checks.
23 | /// This is only included to be compatible with legacy behaviour.
24 | ///
25 | Skip,
26 |
27 | ///
28 | /// Append is now renamed to Resume.
29 | ///
30 | [ObsoleteAttribute("Append is now renamed to Resume to better reflect its behaviour.", true)]
31 | Append,
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/FtpHandlerIndex.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using FluentFTP.Servers.Handlers;
3 |
4 | namespace FluentFTP.Servers {
5 | internal static class FtpHandlerIndex {
6 |
7 | public static List AllServers = new List {
8 | new ApacheFtpServer(),
9 | new BFtpdServer(),
10 | new CerberusServer(),
11 | new CrushFtpServer(),
12 | new FileZillaServer(),
13 | new FritzBoxServer(),
14 | new Ftp2S3GatewayServer(),
15 | new GlFtpdServer(),
16 | new GlobalScapeEftServer(),
17 | new HomegateFtpServer(),
18 | new IBMOS400FtpServer(),
19 | new IBMzOSFtpServer(),
20 | new IDALFtpServer(),
21 | new NonStopTandemServer(),
22 | new OpenVmsServer(),
23 | new ProFtpdServer(),
24 | new PureFtpdServer(),
25 | new PyFtpdLibServer(),
26 | new RumpusServer(),
27 | new ServUServer(),
28 | new SolarisFtpServer(),
29 | new TitanFtpServer(),
30 | new VsFtpdServer(),
31 | new WindowsCEServer(),
32 | new WindowsIISServer(),
33 | new WSFTPServer(),
34 | new WuFtpdServer(),
35 | new XLightServer(),
36 | };
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpOperator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 |
7 | ///
8 | /// For setting up rules
9 | ///
10 | public enum FtpOperator {
11 |
12 | ///
13 | /// If the value is exactly equal to X
14 | ///
15 | Equals,
16 | ///
17 | /// If the value is anything except for X
18 | ///
19 | NotEquals,
20 | ///
21 | /// If the value is less than X
22 | ///
23 | LessThan,
24 | ///
25 | /// If the value is less than or equal to X
26 | ///
27 | LessThanOrEquals,
28 | ///
29 | /// If the value is more than X
30 | ///
31 | MoreThan,
32 | ///
33 | /// If the value is more than or equal to X
34 | ///
35 | MoreThanOrEquals,
36 | ///
37 | /// If the value is between the range of X and Y
38 | ///
39 | BetweenRange,
40 | ///
41 | /// If the value is outside the range of X and Y
42 | ///
43 | OutsideRange,
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/.github/workflows_WIP/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: pull_request
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | Tests:
11 | env:
12 | framework: 'net6.0'
13 | strategy:
14 | matrix:
15 | include:
16 | - ftp: pureftpd
17 | os: ubuntu-latest
18 | - ftp: vsftpd
19 | os: ubuntu-latest
20 | - ftp: pyftpdlib
21 | os: ubuntu-latest
22 |
23 | runs-on: ${{ matrix.os }}
24 |
25 | steps:
26 | - uses: actions/checkout@v3
27 | - name: Setup .NET
28 | uses: actions/setup-dotnet@v2
29 | with:
30 | dotnet-version: 6.0.x
31 | - name: Restore dependencies
32 | run: dotnet restore
33 | - name: Build
34 | run: dotnet build FluentFTP.Tests/FluentFTP.Tests.csproj --no-restore --framework ${{ env.framework }}
35 | - name: Test
36 | env:
37 | FluentFTP__Tests__Integration__FtpServerKey: ${{ matrix.ftp }}
38 | run: dotnet test FluentFTP.Tests/FluentFTP.Tests.csproj --no-build --verbosity normal --framework ${{ env.framework }}
39 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/SetWorkingDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using FluentFTP.Exceptions;
8 |
9 | namespace FluentFTP {
10 | public partial class AsyncFtpClient {
11 |
12 | ///
13 | /// Sets the working directory on the server asynchronously
14 | ///
15 | /// The directory to change to
16 | /// The token that can be used to cancel the entire process
17 | public async Task SetWorkingDirectory(string path, CancellationToken token = default(CancellationToken)) {
18 |
19 | path = path.GetFtpPath();
20 |
21 | LogFunction(nameof(SetWorkingDirectory), new object[] { path });
22 |
23 | FtpReply reply;
24 |
25 | // exit if invalid path
26 | if (path is "." or "./") {
27 | return;
28 | }
29 |
30 | // modify working dir
31 | if (!(reply = await Execute("CWD " + path, token)).Success) {
32 | throw new FtpCommandException(reply);
33 | }
34 |
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FluentFTP/Helpers/LocalPorts.cs:
--------------------------------------------------------------------------------
1 | namespace FluentFTP.Helpers {
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.NetworkInformation;
7 |
8 | ///
9 | /// The local ports.
10 | ///
11 | internal static class LocalPorts {
12 |
13 | internal static readonly Random randomGen = new Random();
14 |
15 | ///
16 | /// Get random local port for the given local IP address
17 | ///
18 | public static int GetRandomAvailable(IPAddress localIpAddress) {
19 | lock (randomGen) {
20 | var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
21 | var tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
22 | var inUsePorts = new HashSet(
23 | tcpConnInfoArray.Where(ipEndPoint => localIpAddress.Equals(ipEndPoint.Address))
24 | .Select(ipEndPoint => ipEndPoint.Port));
25 | int localPort;
26 | do {
27 | localPort = 1025 + randomGen.Next(32000);
28 | }
29 | while (inUsePorts.Contains(localPort));
30 |
31 | return localPort;
32 | }
33 | }
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/ValidateCertficate.cs:
--------------------------------------------------------------------------------
1 | namespace FluentFTP.Client.BaseClient {
2 |
3 | public partial class BaseFtpClient {
4 |
5 | ///
6 | /// Catches the socket stream ssl validation event and fires the event handlers
7 | /// attached to this object for validating SSL certificates
8 | ///
9 | /// The stream that fired the event
10 | /// The event args used to validate the certificate
11 | protected void FireValidateCertficate(FtpSocketStream stream, FtpSslValidationEventArgs e) {
12 | OnValidateCertficate(e);
13 | }
14 |
15 | ///
16 | /// Fires the SSL validation event
17 | ///
18 | /// Event Args
19 | protected void OnValidateCertficate(FtpSslValidationEventArgs e) {
20 |
21 | // automatically validate if ValidateAnyCertificate is set
22 | if (Config.ValidateAnyCertificate) {
23 | e.Accept = true;
24 | return;
25 | }
26 |
27 | // fallback to manual validation using the ValidateCertificate event
28 | m_ValidateCertificate?.Invoke(this, e);
29 |
30 | }
31 |
32 | }
33 | }
--------------------------------------------------------------------------------
/FluentFTP.Dockers/glftpd/run-glftpd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # stdout server info:
4 | cat << EOB
5 | *************************************************
6 | * *
7 | * Docker image: fluentftp glftpd *
8 | * *
9 | *************************************************
10 |
11 | SERVER SETTINGS
12 | ---------------
13 | · FTP User: fluentuser
14 | · FTP Password: fluentpass
15 | EOB
16 |
17 | # start xinetd, because glftpd cannot be run standalone.
18 |
19 | /usr/sbin/xinetd -pidfile /run/xinetd.pid -stayalive -inetd_compat -inetd_ipv6
20 |
21 | # The -n AND the quote user, quote password are NEEDED to make this hack work -
22 | # add the fluentuser to the initial glftpd user database. Can only do this be
23 | # logging on the glftpd and using site commands.
24 |
25 | ftp -n localhost </dev/null /opt/
36 | tail -f /dev/null
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/Disconnect.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace FluentFTP {
6 | public partial class AsyncFtpClient {
7 |
8 | ///
9 | /// Disconnects from the server asynchronously
10 | ///
11 | public async Task Disconnect(CancellationToken token = default(CancellationToken)) {
12 | LogFunction(nameof(Disconnect), null);
13 |
14 | if (IsConnected) {
15 | try {
16 | if (Config.DisconnectWithQuit) {
17 | await Execute("QUIT", token);
18 | }
19 | }
20 | catch (Exception ex) {
21 | LogWithPrefix(FtpTraceLevel.Verbose, "AsyncFtpClient.Disconnect().Execute(\"QUIT\"): " + ex.Message);
22 | }
23 | finally {
24 | // When debugging, the stream might have already been taken down
25 | // from the remote side, thus causing an exception here, so check for null
26 | if (m_stream != null) {
27 | await m_stream.CloseAsync(token);
28 | }
29 | }
30 | }
31 | else {
32 | LogWithPrefix(FtpTraceLevel.Verbose, "Connection already closed, nothing to do.");
33 | }
34 | }
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/CheckFileExistsBySize.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Helpers;
2 | using FluentFTP.Client.Modules;
3 |
4 | namespace FluentFTP.Client.BaseClient {
5 | public partial class BaseFtpClient {
6 |
7 | ///
8 | /// Try using the SIZE command to check if file exists
9 | ///
10 | ///
11 | ///
12 | protected bool? CheckFileExistsBySize(FtpSizeReply sizeReply) {
13 |
14 | // file surely exists
15 | if (sizeReply.Reply.Code[0] == '2') {
16 | return true;
17 | }
18 |
19 | // file surely does not exist
20 | if (sizeReply.Reply.Code[0] == '5' && sizeReply.Reply.Message.ContainsAnyCI(ServerStringModule.fileNotFound)) {
21 | return false;
22 | }
23 |
24 | // Fix #518: This check is too broad and must be disabled, need to fallback to MDTM or NLST instead.
25 | // Fix #179: Add a generic check to since server returns 550 if file not found or no access to file.
26 | /*if (sizeReply.Reply.Code.Substring(0, 3) == "550") {
27 | return false;
28 | }*/
29 |
30 | // fallback to MDTM or NLST
31 | return null;
32 | }
33 |
34 | }
35 | }
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/IOExceptions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Net.Sockets;
3 | using FluentFTP.Client.Modules;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP.Exceptions {
7 | ///
8 | /// Extension methods related to FTP tasks
9 | ///
10 | public static class IOExceptions {
11 |
12 | ///
13 | /// Check if operation can resume after .
14 | ///
15 | /// Received exception.
16 | /// Result of checking.
17 | public static bool IsResumeAllowed(this IOException exception) {
18 | // resume if server disconnects midway (fixes #39 and #410)
19 | if (exception.InnerException != null || exception.Message.ContainsAnyCI(ServerStringModule.unexpectedEOF)) {
20 | if (exception.InnerException is SocketException socketException) {
21 | #if NETSTANDARD || NET5_0_OR_GREATER
22 | return (int)socketException.SocketErrorCode == 10054;
23 | #else
24 | return socketException.ErrorCode == 10054;
25 | #endif
26 | }
27 |
28 | return true;
29 | }
30 |
31 | return false;
32 | }
33 |
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/GetNameListing.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module GetNameListingExample
9 | Sub GetNameListing()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Connect()
12 |
13 | For Each s In conn.GetNameListing()
14 | Dim isDirectory = conn.DirectoryExists(s)
15 | Dim modify = conn.GetModifiedTime(s)
16 | Dim size = If(isDirectory, 0, conn.GetFileSize(s))
17 | Next
18 | End Using
19 | End Sub
20 |
21 | Async Function GetNameListingAsync() As Task
22 | Dim token = New CancellationToken()
23 |
24 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
25 | Await conn.Connect(token)
26 |
27 | For Each s In Await conn.GetNameListing(token)
28 | Dim isDirectory = Await conn.DirectoryExists(s, token)
29 | Dim modify = Await conn.GetModifiedTime(s, token)
30 | Dim size = If(isDirectory, 0, Await conn.GetFileSize(s, -1, token))
31 | Next
32 | End Using
33 | End Function
34 | End Module
35 | End Namespace
36 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/GetModifiedTime.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentFTP.Helpers;
3 | using FluentFTP.Client.Modules;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class FtpClient {
9 |
10 | ///
11 | /// Gets the modified time of a remote file.
12 | ///
13 | /// The full path to the file
14 | /// The modified time, or if there was a problem
15 | public virtual DateTime GetModifiedTime(string path) {
16 | // verify args
17 | if (path.IsBlank()) {
18 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
19 | }
20 |
21 | path = path.GetFtpPath();
22 |
23 | LogFunction(nameof(GetModifiedTime), new object[] { path });
24 |
25 | var date = DateTime.MinValue;
26 | FtpReply reply;
27 |
28 | // get modified date of a file
29 | if ((reply = Execute("MDTM " + path)).Success) {
30 | date = reply.Message.ParseFtpDate(this);
31 | date = ConvertDate(date);
32 | }
33 |
34 | return date;
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/StartListeningOnPort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 | using FluentFTP.Helpers;
4 |
5 | namespace FluentFTP.Client.BaseClient {
6 |
7 | public partial class BaseFtpClient {
8 |
9 | ///
10 | /// Open a local port on the given ActivePort or a random port.
11 | ///
12 | ///
13 | protected void StartListeningOnPort(FtpDataStream stream) {
14 | if (Config.ActivePorts.IsBlank()) {
15 | // Use random port
16 | stream.Listen(m_stream.LocalEndPoint.Address, 0);
17 | }
18 | else {
19 | var success = false;
20 |
21 | // Use one of the specified ports
22 | foreach (var port in Config.ActivePorts) {
23 | try {
24 | stream.Listen(m_stream.LocalEndPoint.Address, port);
25 | success = true;
26 | break;
27 | }
28 | catch (SocketException se) when (se.SocketErrorCode == SocketError.AddressAlreadyInUse) {
29 | }
30 | }
31 |
32 | // No usable port found
33 | if (!success) {
34 | throw new Exception("No valid active data port available!");
35 | }
36 | }
37 | }
38 |
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/BFtpdContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class BFtpdContainer : DockerFtpContainer {
11 |
12 | public BFtpdContainer() {
13 | ServerType = FtpServer.BFTPd;
14 | ServerName = "bftpd";
15 | DockerImage = "bftpd:fluentftp";
16 | //without SSL:
17 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 bftpd:fluentftp";
18 | //with SSL:
19 | // not possible
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/Connect.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module ConnectExample
9 | Sub Connect()
10 | Using conn = New FtpClient()
11 | conn.Host = "localhost"
12 | conn.Credentials = New NetworkCredential("ftptest", "ftptest")
13 | conn.Connect()
14 | End Using
15 | End Sub
16 |
17 | Sub ConnectAlt()
18 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
19 | conn.Connect()
20 | End Using
21 | End Sub
22 |
23 | Async Function ConnectAsync() As Task
24 | Dim token = New CancellationToken()
25 |
26 | Using conn = New AsyncFtpClient()
27 | conn.Host = "localhost"
28 | conn.Credentials = New NetworkCredential("ftptest", "ftptest")
29 | Await conn.Connect(token)
30 | End Using
31 | End Function
32 |
33 | Async Function ConnectAsyncAlt() As Task
34 | Dim token = New CancellationToken()
35 |
36 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
37 | Await conn.Connect(token)
38 | End Using
39 | End Function
40 | End Module
41 | End Namespace
42 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pyftpdlib/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Andriy Kohut
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/ApacheContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class ApacheContainer : DockerFtpContainer {
11 |
12 | public ApacheContainer() {
13 | ServerType = FtpServer.Apache;
14 | ServerName = "apache";
15 | DockerImage = "apache:fluentftp";
16 | //without SSL:
17 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 apache:fluentftp";
18 | //with SSL:
19 | // not possible
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/GlFtpdContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class GlFtpdContainer : DockerFtpContainer {
11 |
12 | public GlFtpdContainer() {
13 | ServerType = FtpServer.glFTPd;
14 | ServerName = "glftpd";
15 | DockerImage = "glftpd:fluentftp";
16 | //without SSL:
17 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 glftpd:fluentftp";
18 | //with SSL:
19 | // not possible
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/FluentFTP.Xunit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 | false
8 | AnyCPU;x64
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 | all
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/FileZillaContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class FileZillaContainer : DockerFtpContainer {
11 |
12 | public FileZillaContainer() {
13 | ServerType = FtpServer.FileZilla;
14 | ServerName = "filezilla";
15 | DockerImage = "filezilla:fluentftp";
16 | //without SSL:
17 | // not possible
18 | //with SSL:
19 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 filezilla:fluentftp";
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/ProFtpdContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class ProFtpdContainer : DockerFtpContainer {
11 |
12 | public ProFtpdContainer() {
13 | ServerType = FtpServer.ProFTPD;
14 | ServerName = "proftpd";
15 | DockerImage = "proftpd:fluentftp";
16 | //without SSL:
17 | // RunCommand = "docker run -d --net host proftpd:fluentftp";
18 | //with SSL:
19 | // RunCommand = "docker run -d --net host -e USE_SSL=YES proftpd:fluentftp";
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/Connect.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class ConnectExample {
9 |
10 | public static void Connect() {
11 |
12 | using (var conn = new FtpClient()) {
13 | conn.Host = "localhost";
14 | conn.Credentials = new NetworkCredential("ftptest", "ftptest");
15 |
16 | conn.Connect();
17 | }
18 | }
19 |
20 | public static void ConnectAlt() {
21 |
22 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
23 |
24 | conn.Connect();
25 | }
26 | }
27 |
28 | public static async Task ConnectAsync() {
29 | var token = new CancellationToken();
30 |
31 | using (var conn = new AsyncFtpClient()) {
32 | conn.Host = "localhost";
33 | conn.Credentials = new NetworkCredential("ftptest", "ftptest");
34 |
35 | await conn.Connect(token);
36 | }
37 | }
38 |
39 | public static async Task ConnectAsyncAlt() {
40 | var token = new CancellationToken();
41 |
42 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
43 |
44 | await conn.Connect(token);
45 | }
46 | }
47 |
48 | }
49 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Attributes/Internal/SkippableFactMessageBus.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Xunit.Attributes;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Xunit.Abstractions;
8 | using Xunit.Sdk;
9 |
10 | namespace FluentFTP.Xunit.Attributes.Internal {
11 | internal class SkippableFactMessageBus : IMessageBus {
12 | readonly IMessageBus innerBus;
13 |
14 | public SkippableFactMessageBus(IMessageBus innerBus) {
15 | this.innerBus = innerBus;
16 | }
17 |
18 | public int DynamicallySkippedTestCount { get; private set; }
19 |
20 | public void Dispose() { }
21 |
22 | public bool QueueMessage(IMessageSinkMessage message) {
23 | var testFailed = message as ITestFailed;
24 | if (testFailed != null) {
25 | var exceptionType = testFailed.ExceptionTypes.FirstOrDefault();
26 | if (exceptionType == typeof(SkipTestException).FullName) {
27 | DynamicallySkippedTestCount++;
28 | return innerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault()));
29 | }
30 | }
31 |
32 | // Nothing we care about, send it on its way
33 | return innerBus.QueueMessage(message);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/PyFtpdLibContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class PyFtpdLibContainer : DockerFtpContainer {
11 | public PyFtpdLibContainer() {
12 | ServerType = FtpServer.PyFtpdLib;
13 | ServerName = "pyftpdlib";
14 | DockerImage = "pyftpdlib:fluentftp";
15 | DockerImageOriginal = "akogut/docker-pyftpdlib";
16 | DockerGithub = "https://github.com/andriykohut/docker-pyftpdlib";
17 | //RunCommand = "docker run -it --rm -p 21:21 pyftpdlib:fluentftp";
18 | FixedUsername = "user";
19 | FixedPassword = "password";
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = base.ExposePortRange(builder, 3000, 3010);
28 | return builder;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpSecurityNotAvailableException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 |
8 | ///
9 | /// Exception is thrown when TLS/SSL encryption could not be negotiated by the FTP server.
10 | ///
11 | #if NETFRAMEWORK
12 | [Serializable]
13 | #endif
14 | public class FtpSecurityNotAvailableException : FtpException {
15 | ///
16 | /// Default constructor
17 | ///
18 | public FtpSecurityNotAvailableException()
19 | : base("FTPS security is not available on the server. To disable FTPS, set the EncryptionMode property to None.") {
20 |
21 | }
22 |
23 | ///
24 | /// Custom error message
25 | ///
26 | /// Error message
27 | public FtpSecurityNotAvailableException(string message)
28 | : base(message) {
29 | }
30 |
31 | #if NETFRAMEWORK
32 | ///
33 | /// Must be implemented so every Serializer can Deserialize the Exception
34 | ///
35 | protected FtpSecurityNotAvailableException(SerializationInfo info, StreamingContext context) : base(info, context) {
36 | }
37 |
38 | #endif
39 | }
40 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/HuaweiServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for Huawei FTP servers
8 | ///
9 | internal class HuaweiServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.Huawei;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Huawei server
24 | // Welcome message: "220 HG510a FTP version 1.0 ready"
25 | // Welcome message: "220 HG520b FTP version 1.0 ready"
26 | // Welcome message: "220 HG530 FTP version 1.0 ready"
27 | if (message.Contains("FTP version 1.0")) {
28 | if (message.Contains("HG51") || message.Contains("HG52")
29 | || message.Contains("HG53") || message.Contains("HG54")) {
30 | return true;
31 | }
32 | }
33 |
34 | return false;
35 | }
36 |
37 | }
38 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/WindowsIISServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for WindowsServer/IIS FTP servers
8 | ///
9 | internal class WindowsIISServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.WindowsServerIIS;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Windows Server/IIS FTP server
24 | // Welcome message: "220-Microsoft FTP Service."
25 | if (message.Contains("Microsoft FTP Service")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | ///
33 | /// Return the default file listing parser to be used with your FTP server.
34 | ///
35 | public override FtpParser GetParser() {
36 | return FtpParser.Windows;
37 | }
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/FluentFTP/Client/BaseClient/Dispose.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Client.BaseClient {
5 |
6 | public partial class BaseFtpClient {
7 |
8 | // Some BaseFtpClient methods refer to a "Dispose". It is necessary to route these
9 | // to the appropriate sync or async dispose, depending on FtpClient or AsyncFtpClient
10 | // having inherited BaseFtpClient
11 |
12 | ///
13 | /// Disconnects from the server
14 | ///
15 | void IInternalFtpClient.DisposeInternal() {
16 | // sync: This dispose percolates down to the BaseFtpClient.Dispose
17 | ((IFtpClient)this).Dispose();
18 | }
19 |
20 | ///
21 | /// Disconnects from the server asynchronously
22 | ///
23 | #if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
24 | async ValueTask IInternalFtpClient.DisposeInternal(CancellationToken token) {
25 | // async: This dispose handled in the AsyncFtpClient
26 | await ((IAsyncFtpClient)this).DisposeAsync();
27 | }
28 | #else
29 | async Task IInternalFtpClient.DisposeInternal(CancellationToken token) {
30 | // async: This dispose handled in the BaseFtpClient
31 | await Task.Run(() => Dispose());
32 | }
33 | #endif
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP/Enums/FtpCompareOption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FluentFTP {
6 | ///
7 | /// Flags that control how file comparison is performed. If you are unsure what to use, set it to Auto.
8 | ///
9 | [Flags]
10 | public enum FtpCompareOption {
11 |
12 | ///
13 | /// Compares the file size and the checksum of the file (using the first supported hash algorithm).
14 | /// The local and remote file sizes and checksums should exactly match for the file to be considered equal.
15 | ///
16 | Auto = 0,
17 |
18 | ///
19 | /// Compares the file size.
20 | /// Both file sizes should exactly match for the file to be considered equal.
21 | ///
22 | Size = 1,
23 |
24 | ///
25 | /// Compares the date modified of the file.
26 | /// Both dates should exactly match for the file to be considered equal.
27 | ///
28 | DateModified = 2,
29 |
30 | ///
31 | /// Compares the checksum or hash of the file using the first supported hash algorithm.
32 | /// Both checksums should exactly match for the file to be considered equal.
33 | ///
34 | Checksum = 4,
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FluentFTP/Proxy/SyncProxy/FtpClientProxy.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.BaseClient;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace FluentFTP.Proxy.SyncProxy {
6 | ///
7 | /// Abstraction of an FtpClient with a proxy
8 | ///
9 | public abstract class FtpClientProxy : FtpClient {
10 | private FtpProxyProfile _proxy;
11 |
12 | /// The proxy connection info.
13 | protected FtpProxyProfile Proxy => _proxy;
14 |
15 | /// A FTP client with a HTTP 1.1 proxy implementation
16 | /// Proxy information
17 | protected FtpClientProxy(FtpProxyProfile proxy) {
18 | _proxy = proxy;
19 |
20 | // set the FTP server details into the client if provided
21 | if (_proxy.FtpHost != null) {
22 | Host = _proxy.FtpHost;
23 | Port = _proxy.FtpPort;
24 | Credentials = _proxy.FtpCredentials;
25 | }
26 | }
27 |
28 | /// Redefine connect for FtpClient : authentication on the Proxy
29 | /// The socket stream.
30 | protected override void Connect(FtpSocketStream stream) {
31 | stream.Connect(Proxy.ProxyHost, Proxy.ProxyPort, Config.InternetProtocolVersions);
32 | }
33 |
34 | }
35 | }
--------------------------------------------------------------------------------
/FluentFTP.Xunit/Docker/Containers/VsFtpdContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DotNet.Testcontainers.Builders;
7 | using DotNet.Testcontainers.Containers;
8 |
9 | namespace FluentFTP.Xunit.Docker.Containers {
10 | internal class VsFtpdContainer : DockerFtpContainer {
11 |
12 | public VsFtpdContainer() {
13 | ServerType = FtpServer.VsFTPd;
14 | ServerName = "vsftpd";
15 | DockerImage = "vsftpd:fluentftp";
16 | //without SSL:
17 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 vsftpd:fluentftp";
18 | //with SSL:
19 | // RunCommand = "docker run --rm -it -p 21:21 -p 21100-21199:21100-21199 -e USE_SSL=YES vsftpd:fluentftp";
20 | }
21 |
22 | ///
23 | /// For help creating this section see https://github.com/testcontainers/testcontainers-dotnet#supported-commands
24 | ///
25 | public override ITestcontainersBuilder Configure(ITestcontainersBuilder builder) {
26 |
27 | builder = builder.WithPortBinding(20);
28 |
29 | builder = ExposePortRange(builder, 21100, 21199);
30 |
31 | return builder;
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/WindowsCEServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for WindowsCE FTP servers
8 | ///
9 | internal class WindowsCEServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.WindowsCE;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given SYST response message.
20 | /// Its a fallback method if the server did not send an identifying welcome message.
21 | ///
22 | public override bool DetectBySyst(string message) {
23 |
24 | // Detect WindowsCE server
25 | // SYST type: "Windows_CE version 7.0"
26 | if (message.Contains("Windows_CE")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | ///
34 | /// Return the default file listing parser to be used with your FTP server.
35 | ///
36 | public override FtpParser GetParser() {
37 | return FtpParser.Windows;
38 | }
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetFilePermissions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using FluentFTP.Helpers;
5 |
6 | namespace FluentFTP {
7 | public partial class AsyncFtpClient {
8 |
9 | ///
10 | /// Retrieve the permissions of the given file/folder as an FtpListItem object with all "Permission" properties set.
11 | /// Throws FtpCommandException if there is an issue.
12 | /// Returns null if the server did not specify a permission value.
13 | /// Use `GetChmod` if you required the integer value instead.
14 | ///
15 | /// The full or relative path to the item
16 | /// The token that can be used to cancel the entire process
17 | public async Task GetFilePermissions(string path, CancellationToken token = default(CancellationToken)) {
18 | // verify args
19 | if (path.IsBlank()) {
20 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
21 | }
22 |
23 | path = path.GetFtpPath();
24 |
25 | LogFunction(nameof(GetFilePermissions), new object[] { path });
26 |
27 | var result = await GetObjectInfo(path, false, token);
28 |
29 | return result;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/bftpd/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # FluentFTP Integration Test Server: bftpd
3 | #
4 |
5 | #
6 | # Stage 1: build
7 | #
8 |
9 | FROM common-debian:fluentftp AS build
10 |
11 | SHELL ["/bin/bash", "-c"]
12 |
13 | WORKDIR /tmp/bftpd
14 | RUN wget --no-check-certificate -O bftpd.tar.gz https://downloads.sourceforge.net/project/bftpd/bftpd/bftpd-6.1/bftpd-6.1.tar.gz && \
15 | tar -xzf bftpd.tar.gz && \
16 | cd bftpd && \
17 | ./configure && \
18 | make -j$(nprocs) && \
19 | make install
20 |
21 | #
22 | # Stage 2: production
23 | #
24 |
25 | FROM common-debian-slim:fluentftp AS production
26 |
27 | LABEL Description="FluentFTP bftpd docker image based on Debian Bullseye."
28 |
29 | SHELL ["/bin/bash", "-c"]
30 |
31 | COPY run-bftpd.sh /usr/sbin/
32 |
33 | COPY --from=build /usr/sbin/bftpd /usr/sbin
34 |
35 | COPY bftpd.conf /usr/etc/
36 |
37 | WORKDIR /
38 | RUN sed -i -e "s/\r//" /usr/etc/bftpd.conf && \
39 | sed -i -e "s/\r//" /usr/sbin/run-bftpd.sh && \
40 | chmod +x /usr/sbin/run-bftpd.sh && \
41 | \
42 | useradd -m -p savatlcb.1m26 fluentuser && \
43 | \
44 | mkdir -p /home/fluentuser/ && \
45 | chown -R fluentuser:users /home/fluentuser
46 |
47 | VOLUME ["/home/fluentuser", "/var/log/bftpd"]
48 |
49 | EXPOSE 20 21
50 |
51 | CMD ["/usr/sbin/run-bftpd.sh"]
52 |
--------------------------------------------------------------------------------
/FluentFTP/Proxy/SyncProxy/FtpClientUserAtHostProxy.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.BaseClient;
2 |
3 | namespace FluentFTP.Proxy.SyncProxy {
4 | /// A FTP client with a user@host proxy identification.
5 | public class FtpClientUserAtHostProxy : FtpClientProxy {
6 | /// A FTP client with a user@host proxy identification.
7 | /// Proxy information
8 | public FtpClientUserAtHostProxy(FtpProxyProfile proxy)
9 | : base(proxy) {
10 | ConnectionType = "User@Host";
11 | }
12 |
13 | ///
14 | /// Creates a new instance of this class. Useful in FTP proxy classes.
15 | ///
16 | protected override BaseFtpClient Create() {
17 | return new FtpClientUserAtHostProxy(Proxy);
18 | }
19 |
20 | /// Redefine the first dialog: auth with proxy information
21 | protected override void Handshake() {
22 | // Proxy authentication eventually needed.
23 | if (Proxy.ProxyCredentials != null) {
24 | Authenticate(Proxy.ProxyCredentials.UserName, Proxy.ProxyCredentials.Password, Proxy.ProxyCredentials.Domain);
25 | }
26 |
27 | // Connection USER@Host means to change user name to add host.
28 | Credentials.UserName = Credentials.UserName + "@" + Host + ":" + Port;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpAuthenticationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 |
8 | ///
9 | /// Exception triggered on FTP authentication failures
10 | ///
11 | #if NETFRAMEWORK
12 | [Serializable]
13 | #endif
14 | public class FtpAuthenticationException : FtpCommandException {
15 | ///
16 | /// Initializes a new instance of a FtpAuthenticationException
17 | ///
18 | /// Status code
19 | /// Associated message
20 | public FtpAuthenticationException(string code, string message) : base(code, message) {
21 | }
22 |
23 | ///
24 | /// Initializes a new instance of a FtpAuthenticationException
25 | ///
26 | /// The FtpReply to build the exception from
27 | public FtpAuthenticationException(FtpReply reply) : base(reply) {
28 | }
29 |
30 | #if NETFRAMEWORK
31 | ///
32 | /// Must be implemented so every Serializer can Deserialize the Exception
33 | ///
34 | protected FtpAuthenticationException(SerializationInfo info, StreamingContext context) : base(info, context) {
35 | }
36 |
37 | #endif
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/FolderMonitor.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Collections.Generic
3 | Imports System.IO
4 | Imports System.Linq
5 | Imports System.Threading
6 | Imports System.Threading.Tasks
7 | Imports FluentFTP
8 | Imports FluentFTP.Monitors
9 |
10 | Namespace Examples
11 | Friend Module FolderMonitorExample
12 | Async Function DownloadStablePdfFilesAsync(ByVal token As CancellationToken) As Task
13 | Dim conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
14 | Await conn.Connect(token)
15 |
16 | Using monitor = New BlockingAsyncFtpMonitor(conn, New List(Of String) From {
17 | "path/to/folder"
18 | })
19 | monitor.PollInterval = TimeSpan.FromMinutes(5)
20 | monitor.WaitForUpload = True
21 |
22 | monitor.ChangeDetected =
23 | Async Function(e)
24 | If True Then
25 | For Each file In e.Added.Where(Function(x) Path.GetExtension(x) = ".pdf")
26 | Dim localFilePath = Path.Combine("C:\LocalFolder", Path.GetFileName(file))
27 | Await e.AsyncFtpClient.DownloadFile(localFilePath, file, token:=e.CancellationToken)
28 | Await e.AsyncFtpClient.DeleteFile(file)
29 | Next
30 | End If
31 | End Function
32 |
33 | Await monitor.Start(token)
34 | End Using
35 | End Function
36 |
37 | End Module
38 | End Namespace
39 |
40 |
--------------------------------------------------------------------------------
/FluentFTP/Model/FtpProxyProfile.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace FluentFTP {
4 |
5 | ///
6 | /// Connection profile for a proxy connection.
7 | ///
8 | public class FtpProxyProfile {
9 |
10 | ///
11 | /// Proxy server host name. Mandatory.
12 | ///
13 | public string ProxyHost { get; set; }
14 |
15 | ///
16 | /// Proxy server port. Mandatory.
17 | ///
18 | public int ProxyPort { get; set; }
19 |
20 | ///
21 | /// Proxy server login credentials. Mandatory if your proxy needs authentication, leave it blank otherwise.
22 | ///
23 | public NetworkCredential ProxyCredentials { get; set; }
24 |
25 | ///
26 | /// FTP server host name. Optional. You can either set it here or set `ftpClient.Host` later on.
27 | ///
28 | public string FtpHost { get; set; }
29 |
30 | ///
31 | /// FTP server port. Optional. You can either set it here or set `ftpClient.Port` later on.
32 | ///
33 | public int FtpPort { get; set; }
34 |
35 | ///
36 | /// FTP server login credentials. Optional. You can either set it here or set `ftpClient.Credentials` later on.
37 | ///
38 | public NetworkCredential FtpCredentials { get; set; }
39 |
40 |
41 | }
42 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/AsyncClient/GetModifiedTime.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentFTP.Helpers;
3 | using FluentFTP.Client.Modules;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace FluentFTP {
8 | public partial class AsyncFtpClient {
9 |
10 | ///
11 | /// Gets the modified time of a remote file asynchronously
12 | ///
13 | /// The full path to the file
14 | /// The token that can be used to cancel the entire process
15 | /// The modified time, or if there was a problem
16 | public async Task GetModifiedTime(string path, CancellationToken token = default(CancellationToken)) {
17 | // verify args
18 | if (path.IsBlank()) {
19 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
20 | }
21 |
22 | path = path.GetFtpPath();
23 |
24 | LogFunction(nameof(GetModifiedTime), new object[] { path });
25 |
26 | var date = DateTime.MinValue;
27 | FtpReply reply;
28 |
29 | // get modified date of a file
30 | if ((reply = await Execute("MDTM " + path, token)).Success) {
31 | date = reply.Message.ParseFtpDate(this);
32 | date = ConvertDate(date);
33 | }
34 |
35 | return date;
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/ConnectFTPSCertificate.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module ConnectFTPSCertificateExample
9 | Sub ConnectFTPSCertificate()
10 | Using conn = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit
12 | AddHandler conn.ValidateCertificate, New FtpSslValidation(AddressOf OnValidateCertificate)
13 | conn.Connect()
14 | End Using
15 | End Sub
16 |
17 | Async Function ConnectFTPSCertificateAsync() As Task
18 | Dim token = New CancellationToken()
19 |
20 | Using conn = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
21 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit
22 | AddHandler conn.ValidateCertificate, New FtpSslValidation(AddressOf OnValidateCertificate)
23 | Await conn.Connect(token)
24 | End Using
25 | End Function
26 |
27 | Private Sub OnValidateCertificate(ByVal control As FtpClient, ByVal e As FtpSslValidationEventArgs)
28 | If e.PolicyErrors <> System.Net.Security.SslPolicyErrors.None Then
29 | ' invalid cert, do you want to accept it?
30 | ' e.Accept = True
31 | Else
32 | e.Accept = True
33 | End If
34 | End Sub
35 | End Module
36 | End Namespace
37 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/GetNameListing.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 | internal static class GetNameListingExample {
9 |
10 | public static void GetNameListing() {
11 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
12 | conn.Connect();
13 |
14 | foreach (var s in conn.GetNameListing()) {
15 | // load some information about the object
16 | // returned from the listing...
17 | var isDirectory = conn.DirectoryExists(s);
18 | var modify = conn.GetModifiedTime(s);
19 | var size = isDirectory ? 0 : conn.GetFileSize(s);
20 | }
21 | }
22 | }
23 |
24 | public static async Task GetNameListingAsync() {
25 | var token = new CancellationToken();
26 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
27 | await conn.Connect(token);
28 |
29 | foreach (var s in await conn.GetNameListing(token)) {
30 | // load some information about the object
31 | // returned from the listing...
32 | var isDirectory = await conn.DirectoryExists(s, token);
33 | var modify = await conn.GetModifiedTime(s, token);
34 | var size = isDirectory ? 0 : await conn.GetFileSize(s, -1, token);
35 | }
36 | }
37 | }
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/FileZillaServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for FileZilla FTP servers
8 | ///
9 | internal class FileZillaServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.FileZilla;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect FileZilla server
24 | // Welcome message: "FileZilla Server 0.9.60 beta"
25 | if (message.Contains("FileZilla Server")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | ///
33 | /// Detect if your FTP server supports the recursive LIST command (LIST -R).
34 | /// If you know for sure that this is supported, return true here.
35 | ///
36 | public override bool RecursiveList() {
37 |
38 | // No support, per: https://trac.filezilla-project.org/ticket/1848
39 | return false;
40 |
41 | }
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/ConnectFTPSCertificate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 | using FluentFTP.Client.BaseClient;
7 |
8 | namespace Examples {
9 | internal static class ConnectFTPSCertificateExample {
10 |
11 | public static void ConnectFTPSCertificate() {
12 | using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
13 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit;
14 | conn.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
15 | conn.Connect();
16 | }
17 | }
18 |
19 | public static async Task ConnectFTPSCertificateAsync() {
20 | var token = new CancellationToken();
21 | using (var conn = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
22 |
23 | conn.Config.EncryptionMode = FtpEncryptionMode.Explicit;
24 | conn.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
25 | await conn.Connect(token);
26 | }
27 | }
28 |
29 | private static void OnValidateCertificate(BaseFtpClient control, FtpSslValidationEventArgs e) {
30 | if (e.PolicyErrors != System.Net.Security.SslPolicyErrors.None) {
31 | // invalid cert, do you want to accept it?
32 | // e.Accept = true;
33 | }
34 | else {
35 | e.Accept = true;
36 | }
37 | }
38 |
39 | }
40 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/UploadManyFiles.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module UploadFilesExample
9 | Sub UploadFiles()
10 | Using ftp = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | ftp.Connect()
12 |
13 | ' upload many files, skip if they already exist on server
14 | ftp.UploadFiles({
15 | "D:\Drivers\test\file0.exe",
16 | "D:\Drivers\test\file1.exe",
17 | "D:\Drivers\test\file2.exe",
18 | "D:\Drivers\test\file3.exe",
19 | "D:\Drivers\test\file4.exe"
20 | }, "/public_html/temp/", FtpRemoteExists.Skip)
21 |
22 | End Using
23 | End Sub
24 |
25 | Async Function UploadFilesAsync() As Task
26 | Dim token = New CancellationToken()
27 |
28 | Using ftp = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
29 | Await ftp.Connect(token)
30 |
31 | ' upload many files, skip if they already exist on server
32 | Await ftp.UploadFiles({
33 | "D:\Drivers\test\file0.exe",
34 | "D:\Drivers\test\file1.exe",
35 | "D:\Drivers\test\file2.exe",
36 | "D:\Drivers\test\file3.exe",
37 | "D:\Drivers\test\file4.exe"
38 | }, "/public_html/temp/", FtpRemoteExists.Skip)
39 |
40 | End Using
41 | End Function
42 | End Module
43 | End Namespace
44 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/AutoConnect.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.Modules;
2 | using FluentFTP.Model.Functions;
3 |
4 | namespace FluentFTP {
5 | public partial class FtpClient {
6 |
7 | ///
8 | /// Automatic FTP and FTPS connection negotiation.
9 | /// This method tries every possible combination of the FTP connection properties, and connects to the first successful profile.
10 | /// Returns the FtpProfile if the connection succeeded, or null if it failed.
11 | /// It will throw exceptions for permanent failures like invalid host or invalid credentials.
12 | ///
13 | public FtpProfile AutoConnect() {
14 | LogFunction(nameof(AutoConnect));
15 |
16 | // connect to the first available connection profile
17 | var results = AutoDetect(new FtpAutoDetectConfig() {
18 | FirstOnly = true,
19 | CloneConnection = false,
20 | });
21 | if (results.Count > 0) {
22 | var profile = results[0];
23 |
24 | // load the profile so final property selections are
25 | // loaded into the current connection
26 | LoadProfile(profile);
27 |
28 | // if we are using SSL, set a basic server acceptance function
29 | ConnectModule.SetDefaultCertificateValidation(this, profile);
30 |
31 | // return the working profile
32 | return profile;
33 | }
34 |
35 | return null;
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/PureFtpdServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for PureFTPd FTP servers
8 | ///
9 | internal class PureFtpdServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.PureFTPd;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Pure-FTPd server
24 | // Welcome message: "---------- Welcome to Pure-FTPd [privsep] [TLS] ----------"
25 | if (message.Contains("Pure-FTPd")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | ///
33 | /// Detect if your FTP server supports the recursive LIST command (LIST -R).
34 | /// If you know for sure that this is supported, return true here.
35 | ///
36 | public override bool RecursiveList() {
37 |
38 | // Has support, per https://download.pureftpd.org/pub/pure-ftpd/doc/README
39 | return true;
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/FluentFTP/Helpers/Enums.cs:
--------------------------------------------------------------------------------
1 | namespace FluentFTP.Helpers {
2 | ///
3 | /// Extension methods related to FTP tasks
4 | ///
5 | public static class Enums {
6 |
7 | ///
8 | /// Validates that the FtpError flags set are not in an invalid combination.
9 | ///
10 | /// The error handling options set
11 | /// True if a valid combination, otherwise false
12 | public static bool IsValidCombination(this FtpError options) {
13 | return options != (FtpError.Stop | FtpError.Throw) &&
14 | options != (FtpError.Throw | FtpError.Stop | FtpError.DeleteProcessed);
15 | }
16 |
17 | ///
18 | /// Checks if the operation was successful or skipped (indicating success).
19 | ///
20 | public static bool IsSuccess(this FtpStatus status) {
21 | return status is FtpStatus.Success or FtpStatus.Skipped;
22 | }
23 |
24 | ///
25 | /// Checks if the operation was skipped (specifically).
26 | ///
27 | public static bool IsSkipped(this FtpStatus status) {
28 | return status is FtpStatus.Skipped;
29 | }
30 |
31 | ///
32 | /// Checks if the operation has failed.
33 | ///
34 | public static bool IsFailure(this FtpStatus status) {
35 | return status == FtpStatus.Failed;
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/VsFtpdServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for VsFTPd FTP servers
8 | ///
9 | internal class VsFtpdServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.VsFTPd;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect vsFTPd server
24 | // Welcome message: "(vsFTPd 3.0.3)"
25 | if (message.Contains("(vsFTPd")) {
26 | return true;
27 | }
28 |
29 | return false;
30 | }
31 |
32 | ///
33 | /// Detect if your FTP server supports the recursive LIST command (LIST -R).
34 | /// If you know for sure that this is supported, return true here.
35 | ///
36 | public override bool RecursiveList() {
37 |
38 | // Has support, but OFF by default, per: https://linux.die.net/man/5/vsftpd.conf
39 | return false; // impossible to detect on a server-by-server basis
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/apache/users.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 |
18 | # user password is "fluentpass" code in md5
19 | ftpserver.user.fluentuser.userpassword=9AB870DD41C07E40C6C96307DB575E56
20 | ftpserver.user.fluentuser.homedirectory=./res/home
21 | ftpserver.user.fluentuser.enableflag=true
22 | ftpserver.user.fluentuser.writepermission=true
23 | ftpserver.user.fluentuser.maxloginnumber=0
24 | ftpserver.user.fluentuser.maxloginperip=0
25 | ftpserver.user.fluentuser.idletime=0
26 | ftpserver.user.fluentuser.uploadrate=0
27 | ftpserver.user.fluentuser.downloadrate=0
28 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DownloadManyFiles.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module DownloadFilesExample
9 | Sub DownloadFiles()
10 | Using ftp = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | ftp.Connect()
12 |
13 | ' download many files, skip if they already exist on disk
14 | ftp.DownloadFiles("D:\Drivers\test\", {
15 | "/public_html/temp/file0.exe",
16 | "/public_html/temp/file1.exe",
17 | "/public_html/temp/file2.exe",
18 | "/public_html/temp/file3.exe",
19 | "/public_html/temp/file4.exe"
20 | }, FtpLocalExists.Skip)
21 |
22 | End Using
23 | End Sub
24 |
25 | Async Function DownloadFilesAsync() As Task
26 | Dim token = New CancellationToken()
27 |
28 | Using ftp = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
29 | Await ftp.Connect(token)
30 |
31 | ' download many files, skip if they already exist on disk
32 | Await ftp.DownloadFiles("D:\Drivers\test\", {
33 | "/public_html/temp/file0.exe",
34 | "/public_html/temp/file1.exe",
35 | "/public_html/temp/file2.exe",
36 | "/public_html/temp/file3.exe",
37 | "/public_html/temp/file4.exe"
38 | }, FtpLocalExists.Skip)
39 |
40 | End Using
41 | End Function
42 | End Module
43 | End Namespace
44 |
--------------------------------------------------------------------------------
/FluentFTP/Servers/Handlers/NonStopTandemServer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace FluentFTP.Servers.Handlers {
5 |
6 | ///
7 | /// Server-specific handling for NonStop/Tandem FTP servers
8 | ///
9 | internal class NonStopTandemServer : FtpBaseServer {
10 |
11 | ///
12 | /// Return the FtpServer enum value corresponding to your server, or Unknown if its a custom implementation.
13 | ///
14 | public override FtpServer ToEnum() {
15 | return FtpServer.NonStopTandem;
16 | }
17 |
18 | ///
19 | /// Return true if your server is detected by the given FTP server welcome message.
20 | ///
21 | public override bool DetectByWelcome(string message) {
22 |
23 | // Detect Tandem/NonStop server
24 | // Welcome message: "220 mysite.com FTP SERVER T9552H02 (Version H02 TANDEM 11SEP2008) ready."
25 | // Welcome message: "220 FTP SERVER T9552G08 (Version G08 TANDEM 15JAN2008) ready."
26 | if (message.Contains("FTP SERVER ") && message.Contains(" TANDEM ")) {
27 | return true;
28 | }
29 |
30 | return false;
31 | }
32 |
33 | ///
34 | /// Return the default file listing parser to be used with your FTP server.
35 | ///
36 | public override FtpParser GetParser() {
37 | return FtpParser.NonStop;
38 | }
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NETFRAMEWORK
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace FluentFTP.Exceptions {
7 | ///
8 | /// FTP related error
9 | ///
10 | #if NETFRAMEWORK
11 | [Serializable]
12 | #endif
13 | public class FtpException : Exception {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The error message
18 | public FtpException(string message) : base(message) {
19 | }
20 |
21 | ///
22 | /// Initializes a new instance of the class with an inner exception.
23 | ///
24 | /// The error message that explains the reason for the exception.
25 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
26 | public FtpException(string message, Exception innerException) : base(message, innerException) {
27 | }
28 |
29 | #if NETFRAMEWORK
30 | ///
31 | /// Must be implemented so every Serializer can Deserialize the Exception
32 | ///
33 | protected FtpException(SerializationInfo info, StreamingContext context) : base(info, context) {
34 | }
35 |
36 | #endif
37 | }
38 | }
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/SetDataType.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Exceptions;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace FluentFTP {
6 | public partial class FtpClient {
7 |
8 | /// Sets the data type of information sent over the data stream
9 | /// Thrown when a FTP Command error condition occurs.
10 | /// Thrown when a FTP error condition occurs.
11 | /// ASCII/Binary.
12 | /// This method doesn't do any locking to prevent recursive lock scenarios. Callers must do their own locking.
13 | protected void SetDataType(FtpDataType type) {
14 | // FIX : #291 only change the data type if different
15 | if (Status.CurrentDataType != type) {
16 | FtpReply reply;
17 | switch (type) {
18 | case FtpDataType.ASCII:
19 | if (!(reply = Execute("TYPE A")).Success) {
20 | throw new FtpCommandException(reply);
21 | }
22 |
23 | break;
24 |
25 | case FtpDataType.Binary:
26 | if (!(reply = Execute("TYPE I")).Success) {
27 | throw new FtpCommandException(reply);
28 | }
29 |
30 | break;
31 |
32 | default:
33 | throw new FtpException("Unsupported data type: " + type.ToString());
34 | }
35 |
36 | Status.CurrentDataType = type;
37 | }
38 | }
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/FluentFTP.Dockers/filezilla/users.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | This user can impersonate any system user.
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | l9jcg8P68htZEZF7iIy6GhrbS8HLFGSikYzaUAnHo5E
23 | oFoJsx+xI6ZIEg9dc7fJUnLqjHWklAi2QcuHe5QVhTE
24 | 100000
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/FluentFTP/Client/SyncClient/EmptyDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using FluentFTP.Helpers;
4 | using FluentFTP.Client.Modules;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace FluentFTP {
9 | public partial class FtpClient {
10 |
11 | ///
12 | /// Deletes the contents of the specified directory, without deleting the directory itself.
13 | ///
14 | /// The full or relative path of the directorys contents to delete
15 | public void EmptyDirectory(string path) {
16 | EmptyDirectory(path, FtpListOption.Recursive);
17 | }
18 |
19 | ///
20 | /// Deletes the contents of the specified directory, without deleting the directory itself.
21 | ///
22 | /// The full or relative path of the directorys contents to delete
23 | /// Useful to delete hidden files or dot-files.
24 | public void EmptyDirectory(string path, FtpListOption options = FtpListOption.Recursive) {
25 |
26 | // verify args
27 | if (path.IsBlank()) {
28 | throw new ArgumentException("Required parameter is null or blank.", nameof(path));
29 | }
30 |
31 | path = path.GetFtpPath();
32 |
33 | LogFunction(nameof(EmptyDirectory), new object[] { path, options });
34 | DeleteDirInternal(path, true, options, false, true);
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FluentFTP.Dockers/pureftpd/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # FluentFTP Integration Test Server: pureftpd
3 | #
4 |
5 | #
6 | # Stage 1: build & production
7 | #
8 |
9 | FROM common-debian-slim:fluentftp AS build
10 |
11 | LABEL Description="FluentFTP pureftpd docker image based on Debian Bullseye."
12 |
13 | SHELL ["/bin/bash", "-c"]
14 |
15 | ARG DEBIAN_FRONTEND=noninteractive
16 | ARG APT_CMD='apt install -y --no-install-recommends'
17 |
18 | COPY sources.list /etc/apt/sources.list
19 |
20 | RUN apt update && \
21 | \
22 | $APT_CMD \
23 | openssl \
24 | pure-ftpd
25 |
26 | COPY run-pureftpd.sh /usr/sbin/
27 |
28 | RUN sed -i -e "s/\r//" /usr/sbin/run-pureftpd.sh && \
29 | chmod +x /usr/sbin/run-pureftpd.sh && \
30 | \
31 | useradd -m -p savatlcb.1m26 fluentuser && \
32 | \
33 | mkdir -p /home/fluentuser/ && \
34 | chown -R fluentuser:users /home/fluentuser && \
35 | \
36 | openssl req -x509 -newkey rsa:4096 \
37 | -keyout /etc/ssl/private/pure-ftpd.key -out /etc/ssl/certs/pure-ftpd.crt \
38 | -subj "/C=US/ST=State/L=/O=Dev/CN=fluentftp" \
39 | -nodes -days 3650 && \
40 | \
41 | chmod 0600 /etc/ssl/private/pure-ftpd.key && \
42 | chmod 0640 /etc/ssl/private/pure-ftpd.key && \
43 | \
44 | cat /etc/ssl/certs/pure-ftpd.crt /etc/ssl/private/pure-ftpd.key > /etc/ssl/private/pure-ftpd.pem
45 |
46 | VOLUME ["/home/fluentuser", "/var/log/pureftpd"]
47 |
48 | EXPOSE 20 21
49 |
50 | CMD ["/usr/sbin/run-pureftpd.sh"]
51 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DownloadDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Collections.Generic
3 | Imports System.Net
4 | Imports System.Threading
5 | Imports System.Threading.Tasks
6 | Imports FluentFTP
7 | Imports FluentFTP.Rules
8 |
9 | Namespace Examples
10 | Friend Module DownloadDirectoryExample
11 | Sub DownloadDirectory()
12 | Using ftp = New FtpClient("127.0.0.1", "ftptest", "ftptest")
13 | ftp.Connect()
14 |
15 | ' download a folder And all its files
16 | ftp.DownloadDirectory("C:\website\logs\", "/public_html/logs", FtpFolderSyncMode.Update)
17 |
18 | ' download a folder And all its files, And delete extra files on disk
19 | ftp.DownloadDirectory("C:\website\dailybackup\", "/public_html/", FtpFolderSyncMode.Mirror)
20 |
21 | End Using
22 | End Sub
23 |
24 | Async Function DownloadDirectoryAsync() As Task
25 | Dim token = New CancellationToken()
26 |
27 | Using ftp = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
28 | Await ftp.Connect(token)
29 |
30 | ' download a folder And all its files
31 | Await ftp.DownloadDirectory("C:\website\logs\", "/public_html/logs", FtpFolderSyncMode.Update)
32 |
33 | ' download a folder And all its files, And delete extra files on disk
34 | Await ftp.DownloadDirectory("C:\website\dailybackup\", "/public_html/", FtpFolderSyncMode.Mirror)
35 |
36 | End Using
37 | End Function
38 | End Module
39 | End Namespace
40 |
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/UploadDirectory.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Collections.Generic
3 | Imports System.Net
4 | Imports System.Threading
5 | Imports System.Threading.Tasks
6 | Imports FluentFTP
7 | Imports FluentFTP.Rules
8 |
9 | Namespace Examples
10 | Friend Module UploadDirectoryExample
11 | Sub UploadDirectory()
12 | Using ftp = New FtpClient("127.0.0.1", "ftptest", "ftptest")
13 | ftp.Connect()
14 |
15 | ' upload a folder and all its files
16 | ftp.UploadDirectory("C:\website\videos\", "/public_html/videos", FtpFolderSyncMode.Update)
17 |
18 | ' upload a folder and all its files, and delete extra files on the server
19 | ftp.UploadDirectory("C:\website\assets\", "/public_html/assets", FtpFolderSyncMode.Mirror)
20 |
21 | End Using
22 | End Sub
23 |
24 | Async Function UploadDirectoryAsync() As Task
25 | Dim token = New CancellationToken()
26 |
27 | Using ftp = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
28 | Await ftp.Connect(token)
29 |
30 | ' upload a folder and all its files
31 | Await ftp.UploadDirectory("C:\website\videos\", "/public_html/videos", FtpFolderSyncMode.Update)
32 |
33 | ' upload a folder and all its files, and delete extra files on the server
34 | Await ftp.UploadDirectory("C:\website\assets\", "/public_html/assets", FtpFolderSyncMode.Mirror)
35 |
36 | End Using
37 | End Function
38 | End Module
39 | End Namespace
40 |
--------------------------------------------------------------------------------
/FluentFTP.Tests/Integration/System/IntegrationTestRunner.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Tests.Integration.Tests;
2 | using FluentFTP.Xunit.Docker;
3 | using System;
4 | using System.Threading.Tasks;
5 | using Xunit;
6 |
7 | namespace FluentFTP.Tests.Integration.System {
8 | internal static class IntegrationTestRunner {
9 |
10 | public static async Task Run(FtpServer serverType, UseStream useStream, bool useSsl = false) {
11 |
12 | // If we are in CI pipeline
13 | if (DockerFtpConfig.IsCI) {
14 |
15 | // just let the test pass
16 | return;
17 | }
18 |
19 | // spin up a new docker
20 | using var server = new DockerFtpServer(serverType, useStream.ToString(), useSsl);
21 |
22 | try {
23 | // TODO: create a better system instead of calling each test suite manually
24 |
25 | // run all types of sync tests
26 | new ConnectTests(server, useStream).RunAllTests();
27 | new FileTransferTests(server, useStream).RunAllTests();
28 | new ListingTests(server, useStream).RunAllTests();
29 |
30 | // run all types of async tests
31 | await new ConnectTests(server, useStream).RunAllTestsAsync();
32 | await new FileTransferTests(server, useStream).RunAllTestsAsync();
33 | await new ListingTests(server, useStream).RunAllTestsAsync();
34 |
35 | }
36 | catch (Exception ex) {
37 | Assert.True(false, $"Integration test failed : " + ex.ToString());
38 | }
39 |
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/UploadManyFiles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 |
9 | internal static class UploadFilesExample {
10 |
11 | public static void UploadFiles() {
12 | using (var ftp = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
13 | ftp.Connect();
14 |
15 | // upload many files, skip if they already exist on server
16 | ftp.UploadFiles(
17 | new[] {
18 | @"D:\Drivers\test\file0.exe",
19 | @"D:\Drivers\test\file1.exe",
20 | @"D:\Drivers\test\file2.exe",
21 | @"D:\Drivers\test\file3.exe",
22 | @"D:\Drivers\test\file4.exe"
23 | },
24 | "/public_html/temp/", FtpRemoteExists.Skip);
25 |
26 | }
27 | }
28 |
29 | public static async Task UploadFilesAsync() {
30 | var token = new CancellationToken();
31 | using (var ftp = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
32 | await ftp.Connect(token);
33 |
34 | // upload many files, skip if they already exist on server
35 | await ftp.UploadFiles(
36 | new[] {
37 | @"D:\Drivers\test\file0.exe",
38 | @"D:\Drivers\test\file1.exe",
39 | @"D:\Drivers\test\file2.exe",
40 | @"D:\Drivers\test\file3.exe",
41 | @"D:\Drivers\test\file4.exe"
42 | },
43 | "/public_html/temp/", FtpRemoteExists.Skip, token: token);
44 |
45 | }
46 | }
47 |
48 | }
49 | }
--------------------------------------------------------------------------------
/FluentFTP/Exceptions/FtpInvalidCertificateException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Authentication;
3 | #if NETFRAMEWORK
4 | using System.Runtime.Serialization;
5 | #endif
6 |
7 | namespace FluentFTP.Exceptions {
8 |
9 | ///
10 | /// Exception is thrown when TLS/SSL encryption could not be negotiated by the FTP server.
11 | ///
12 | #if NETFRAMEWORK
13 | [Serializable]
14 | #endif
15 | public class FtpInvalidCertificateException : FtpException {
16 |
17 | ///
18 | /// AuthenticationException that caused this.
19 | ///
20 | public new Exception InnerException { get; private set; }
21 |
22 | ///
23 | /// Default constructor
24 | ///
25 | public FtpInvalidCertificateException(Exception innerException)
26 | : base("FTPS security could not be established on the server. The certificate was not accepted.", innerException) {
27 | }
28 |
29 | ///
30 | /// Custom error message
31 | ///
32 | /// Error message
33 | public FtpInvalidCertificateException(string message)
34 | : base(message) {
35 | }
36 |
37 | #if NETFRAMEWORK
38 | ///
39 | /// Must be implemented so every Serializer can Deserialize the Exception
40 | ///
41 | protected FtpInvalidCertificateException(SerializationInfo info, StreamingContext context) : base(info, context) {
42 | }
43 |
44 | #endif
45 | }
46 | }
--------------------------------------------------------------------------------
/FluentFTP/Proxy/AsyncProxy/AsyncFtpClientUserAtHostProxy.cs:
--------------------------------------------------------------------------------
1 | using FluentFTP.Client.BaseClient;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace FluentFTP.Proxy.AsyncProxy {
6 | /// A FTP client with a user@host proxy identification.
7 | public class AsyncFtpClientUserAtHostProxy : AsyncFtpClientProxy {
8 | /// A FTP client with a user@host proxy identification.
9 | /// Proxy information
10 | public AsyncFtpClientUserAtHostProxy(FtpProxyProfile proxy)
11 | : base(proxy) {
12 | ConnectionType = "User@Host";
13 | }
14 |
15 | ///
16 | /// Creates a new instance of this class. Useful in FTP proxy classes.
17 | ///
18 | protected override BaseFtpClient Create() {
19 | return new AsyncFtpClientUserAtHostProxy(Proxy);
20 | }
21 |
22 | /// Redefine the first dialog: auth with proxy information
23 | protected override async Task HandshakeAsync(CancellationToken token = default) {
24 |
25 | // Proxy authentication eventually needed.
26 | if (Proxy.ProxyCredentials != null) {
27 | await Authenticate(Proxy.ProxyCredentials.UserName, Proxy.ProxyCredentials.Password, Proxy.ProxyCredentials.Domain, token);
28 | }
29 |
30 | // Connection USER@Host means to change user name to add host.
31 | Credentials.UserName = Credentials.UserName + "@" + Host + ":" + Port;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/DownloadManyFiles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using FluentFTP;
6 |
7 | namespace Examples {
8 |
9 | internal static class DownloadFilesExample {
10 |
11 | public static void DownloadFiles() {
12 | using (var ftp = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
13 | ftp.Connect();
14 |
15 | // download many files, skip if they already exist on disk
16 | ftp.DownloadFiles(@"D:\Drivers\test\",
17 | new[] {
18 | @"/public_html/temp/file0.exe",
19 | @"/public_html/temp/file1.exe",
20 | @"/public_html/temp/file2.exe",
21 | @"/public_html/temp/file3.exe",
22 | @"/public_html/temp/file4.exe"
23 | }, FtpLocalExists.Skip);
24 |
25 | }
26 | }
27 |
28 | public static async Task DownloadFilesAsync() {
29 | var token = new CancellationToken();
30 | using (var ftp = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
31 | await ftp.Connect(token);
32 |
33 | // download many files, skip if they already exist on disk
34 | await ftp.DownloadFiles(@"D:\Drivers\test\",
35 | new[] {
36 | @"/public_html/temp/file0.exe",
37 | @"/public_html/temp/file1.exe",
38 | @"/public_html/temp/file2.exe",
39 | @"/public_html/temp/file3.exe",
40 | @"/public_html/temp/file4.exe"
41 | }, FtpLocalExists.Skip, token: token);
42 |
43 | }
44 | }
45 |
46 | }
47 | }
--------------------------------------------------------------------------------
/FluentFTP.VBExamples/DownloadFile.vb:
--------------------------------------------------------------------------------
1 | Imports System
2 | Imports System.Net
3 | Imports System.Threading
4 | Imports System.Threading.Tasks
5 | Imports FluentFTP
6 |
7 | Namespace Examples
8 | Friend Module DownloadFileExample
9 | Sub DownloadFile()
10 | Using ftp = New FtpClient("127.0.0.1", "ftptest", "ftptest")
11 | ftp.Connect()
12 |
13 | ' download a file and ensure the local directory is created
14 | ftp.DownloadFile("D:\Github\FluentFTP\README.md", "/public_html/temp/README.md")
15 |
16 | ' download a file and ensure the local directory is created, verify the file after download
17 | ftp.DownloadFile("D:\Github\FluentFTP\README.md", "/public_html/temp/README.md", FtpLocalExists.Overwrite, FtpVerify.Retry)
18 |
19 | End Using
20 | End Sub
21 |
22 | Async Function DownloadFileAsync() As Task
23 | Dim token = New CancellationToken()
24 |
25 | Using ftp = New AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")
26 | Await ftp.Connect(token)
27 |
28 | ' download a file and ensure the local directory is created
29 | Await ftp.DownloadFile("D:\Github\FluentFTP\README.md", "/public_html/temp/README.md")
30 |
31 | ' download a file and ensure the local directory is created, verify the file after download
32 | Await ftp.DownloadFile("D:\Github\FluentFTP\README.md", "/public_html/temp/README.md", FtpLocalExists.Overwrite, FtpVerify.Retry)
33 |
34 | End Using
35 | End Function
36 | End Module
37 | End Namespace
38 |
--------------------------------------------------------------------------------
/FluentFTP.CSharpExamples/DownloadDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using FluentFTP;
7 | using FluentFTP.Rules;
8 |
9 | namespace Examples {
10 |
11 | internal static class DownloadDirectoryExample {
12 |
13 | public static void DownloadDirectory() {
14 | using (var ftp = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
15 | ftp.Connect();
16 |
17 |
18 | // download a folder and all its files
19 | ftp.DownloadDirectory(@"C:\website\logs\", @"/public_html/logs", FtpFolderSyncMode.Update);
20 |
21 | // download a folder and all its files, and delete extra files on disk
22 | ftp.DownloadDirectory(@"C:\website\dailybackup\", @"/public_html/", FtpFolderSyncMode.Mirror);
23 |
24 | }
25 | }
26 |
27 | public static async Task DownloadDirectoryAsync() {
28 | var token = new CancellationToken();
29 | using (var ftp = new AsyncFtpClient("127.0.0.1", "ftptest", "ftptest")) {
30 | await ftp.Connect(token);
31 |
32 |
33 | // download a folder and all its files
34 | await ftp.DownloadDirectory(@"C:\website\logs\", @"/public_html/logs", FtpFolderSyncMode.Update, token: token);
35 |
36 | // download a folder and all its files, and delete extra files on disk
37 | await ftp.DownloadDirectory(@"C:\website\dailybackup\", @"/public_html/", FtpFolderSyncMode.Mirror, token: token);
38 |
39 | }
40 | }
41 |
42 | }
43 | }
--------------------------------------------------------------------------------