ShareX/ShareX.UploadersLib/FileUploaders/FTP.cs

505 lines
15 KiB
C#
Raw Normal View History

2013-11-03 23:53:49 +13:00
#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
2024-01-03 12:57:14 +13:00
Copyright (c) 2007-2024 ShareX Team
2013-11-03 23:53:49 +13:00
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at <http://www.gnu.org/licenses/>.
*/
#endregion License Information (GPL v3)
using FluentFTP;
2023-02-14 16:23:34 +13:00
using FluentFTP.Exceptions;
2014-12-11 09:25:20 +13:00
using ShareX.HelpersLib;
2016-06-28 05:20:55 +12:00
using ShareX.UploadersLib.Properties;
2013-11-03 23:53:49 +13:00
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
2013-11-03 23:53:49 +13:00
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Windows.Forms;
2013-11-03 23:53:49 +13:00
2014-12-11 09:25:20 +13:00
namespace ShareX.UploadersLib.FileUploaders
2013-11-03 23:53:49 +13:00
{
public class FTPFileUploaderService : FileUploaderService
{
public override FileDestination EnumValue { get; } = FileDestination.FTP;
2016-06-28 05:20:55 +12:00
public override Image ServiceImage => Resources.folder_network;
public override bool CheckConfig(UploadersConfig config)
{
return config.FTPAccountList != null && config.FTPAccountList.IsValidIndex(config.FTPSelectedFile);
}
public override GenericUploader CreateUploader(UploadersConfig config, TaskReferenceHelper taskInfo)
{
int index;
if (taskInfo.OverrideFTP)
{
index = taskInfo.FTPIndex.BetweenOrDefault(0, config.FTPAccountList.Count - 1);
}
else
{
switch (taskInfo.DataType)
{
case EDataType.Image:
index = config.FTPSelectedImage;
break;
case EDataType.Text:
index = config.FTPSelectedText;
break;
default:
case EDataType.File:
index = config.FTPSelectedFile;
break;
}
}
FTPAccount account = config.FTPAccountList.ReturnIfValidIndex(index);
if (account != null)
{
if (account.Protocol == FTPProtocol.FTP || account.Protocol == FTPProtocol.FTPS)
{
return new FTP(account);
}
else if (account.Protocol == FTPProtocol.SFTP)
{
return new SFTP(account);
}
}
return null;
}
public override TabPage GetUploadersConfigTabPage(UploadersConfigForm form) => form.tpFTP;
}
public sealed class FTP : FileUploader, IDisposable
2013-11-03 23:53:49 +13:00
{
public FTPAccount Account { get; private set; }
2013-11-03 23:53:49 +13:00
2014-05-31 02:59:08 +12:00
public bool IsConnected
{
get
{
return client != null && client.IsConnected;
}
}
private FtpClient client;
2013-11-03 23:53:49 +13:00
public FTP(FTPAccount account)
2013-11-03 23:53:49 +13:00
{
Account = account;
client = new FtpClient()
{
Host = Account.Host,
Port = Account.Port,
Credentials = new NetworkCredential(Account.Username, Account.Password)
};
if (account.IsActive)
2013-11-03 23:53:49 +13:00
{
2022-12-03 16:46:47 +13:00
client.Config.DataConnectionType = FtpDataConnectionType.AutoActive;
2013-11-03 23:53:49 +13:00
}
else
{
2022-12-03 16:46:47 +13:00
client.Config.DataConnectionType = FtpDataConnectionType.AutoPassive;
}
2014-05-25 10:24:51 +12:00
if (account.Protocol == FTPProtocol.FTPS)
{
2014-05-25 10:24:51 +12:00
switch (Account.FTPSEncryption)
{
default:
case FTPSEncryption.Explicit:
2022-12-03 16:46:47 +13:00
client.Config.EncryptionMode = FtpEncryptionMode.Explicit;
2014-05-25 10:24:51 +12:00
break;
case FTPSEncryption.Implicit:
2022-12-03 16:46:47 +13:00
client.Config.EncryptionMode = FtpEncryptionMode.Implicit;
2014-05-25 10:24:51 +12:00
break;
}
2022-12-03 16:46:47 +13:00
client.Config.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
client.Config.DataConnectionEncryption = true;
2013-11-03 23:53:49 +13:00
2014-05-25 10:24:51 +12:00
if (!string.IsNullOrEmpty(account.FTPSCertificateLocation) && File.Exists(account.FTPSCertificateLocation))
2013-11-03 23:53:49 +13:00
{
2014-05-25 10:24:51 +12:00
X509Certificate cert = X509Certificate2.CreateFromSignedFile(Account.FTPSCertificateLocation);
2022-12-03 16:46:47 +13:00
client.Config.ClientCertificates.Add(cert);
2013-11-03 23:53:49 +13:00
}
else
{
2014-10-19 10:48:47 +13:00
client.ValidateCertificate += (control, e) =>
{
if (e.PolicyErrors != SslPolicyErrors.None)
{
e.Accept = true;
}
};
2013-11-03 23:53:49 +13:00
}
}
}
2013-11-03 23:53:49 +13:00
public override UploadResult Upload(Stream stream, string fileName)
{
UploadResult result = new UploadResult();
2013-11-03 23:53:49 +13:00
string subFolderPath = Account.GetSubFolderPath(null, NameParserType.FilePath);
2017-04-25 02:01:35 +12:00
string path = URLHelpers.CombineURL(subFolderPath, fileName);
2015-12-10 07:38:57 +13:00
string url = Account.GetUriPath(fileName, subFolderPath);
OnEarlyURLCopyRequested(url);
try
{
IsUploading = true;
2015-12-10 07:38:57 +13:00
bool uploadResult = UploadData(stream, path);
if (uploadResult && !StopUploadRequested && !IsError)
{
result.URL = url;
}
}
finally
2013-11-03 23:53:49 +13:00
{
Dispose();
IsUploading = false;
}
2013-11-03 23:53:49 +13:00
return result;
2013-11-03 23:53:49 +13:00
}
public override void StopUpload()
2013-11-03 23:53:49 +13:00
{
if (IsUploading && !StopUploadRequested)
2013-11-03 23:53:49 +13:00
{
StopUploadRequested = true;
try
{
Disconnect();
}
catch (Exception e)
{
DebugHelper.WriteException(e);
}
2013-11-03 23:53:49 +13:00
}
}
public bool Connect()
2013-11-03 23:53:49 +13:00
{
if (!client.IsConnected)
2013-11-03 23:53:49 +13:00
{
client.Connect();
2013-11-03 23:53:49 +13:00
}
return client.IsConnected;
2013-11-03 23:53:49 +13:00
}
public void Disconnect()
{
if (client != null)
2013-11-03 23:53:49 +13:00
{
client.Disconnect();
2013-11-03 23:53:49 +13:00
}
}
2014-05-25 12:09:49 +12:00
public bool UploadData(Stream localStream, string remotePath)
2013-11-03 23:53:49 +13:00
{
if (Connect())
{
try
{
2022-02-08 04:06:15 +13:00
return UploadDataInternal(localStream, remotePath);
2013-11-03 23:53:49 +13:00
}
2014-05-25 12:09:49 +12:00
catch (FtpCommandException e)
2013-11-03 23:53:49 +13:00
{
2014-05-25 12:09:49 +12:00
// Probably directory not exist, try creating it
if (e.CompletionCode == "550" || e.CompletionCode == "553")
2013-11-03 23:53:49 +13:00
{
2014-05-31 02:59:08 +12:00
CreateMultiDirectory(URLHelpers.GetDirectoryPath(remotePath));
2022-02-08 04:06:15 +13:00
return UploadDataInternal(localStream, remotePath);
2013-11-03 23:53:49 +13:00
}
2014-05-25 12:09:49 +12:00
throw e;
2013-11-03 23:53:49 +13:00
}
}
2014-05-25 12:09:49 +12:00
return false;
2013-11-03 23:53:49 +13:00
}
2022-02-08 04:06:15 +13:00
private bool UploadDataInternal(Stream localStream, string remotePath)
{
bool result;
using (Stream remoteStream = client.OpenWrite(remotePath))
{
result = TransferData(localStream, remoteStream);
}
FtpReply ftpReply = client.GetReply();
return result && ftpReply.Success;
}
2013-11-03 23:53:49 +13:00
public void UploadData(byte[] data, string remotePath)
{
using (MemoryStream stream = new MemoryStream(data, false))
{
UploadData(stream, remotePath);
}
}
public void UploadFile(string localPath, string remotePath)
{
using (FileStream stream = new FileStream(localPath, FileMode.Open))
{
UploadData(stream, remotePath);
}
}
public void UploadImage(Image image, string remotePath)
{
using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, image.RawFormat);
UploadData(stream, remotePath);
}
}
public void UploadText(string text, string remotePath)
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(text), false))
{
UploadData(stream, remotePath);
}
}
public void UploadFiles(string[] localPaths, string remotePath)
{
foreach (string file in localPaths)
{
if (!string.IsNullOrEmpty(file))
{
2021-12-12 10:21:19 +13:00
string fileName = Path.GetFileName(file);
2013-11-03 23:53:49 +13:00
if (File.Exists(file))
{
2021-12-12 10:21:19 +13:00
UploadFile(file, URLHelpers.CombineURL(remotePath, fileName));
2013-11-03 23:53:49 +13:00
}
else if (Directory.Exists(file))
{
List<string> filesList = new List<string>();
filesList.AddRange(Directory.GetFiles(file));
filesList.AddRange(Directory.GetDirectories(file));
2021-12-12 10:21:19 +13:00
string path = URLHelpers.CombineURL(remotePath, fileName);
2014-05-31 02:59:08 +12:00
CreateDirectory(path);
2013-11-03 23:53:49 +13:00
UploadFiles(filesList.ToArray(), path);
}
}
}
}
2014-05-25 12:09:49 +12:00
public void DownloadFile(string remotePath, Stream localStream)
2013-11-03 23:53:49 +13:00
{
2014-05-25 12:09:49 +12:00
if (Connect())
2013-11-03 23:53:49 +13:00
{
2014-05-25 12:09:49 +12:00
using (Stream remoteStream = client.OpenRead(remotePath))
{
TransferData(remoteStream, localStream);
}
client.GetReply();
2013-11-03 23:53:49 +13:00
}
}
2014-05-25 12:09:49 +12:00
public void DownloadFile(string remotePath, string localPath)
2013-11-03 23:53:49 +13:00
{
2014-05-25 12:09:49 +12:00
using (FileStream fs = new FileStream(localPath, FileMode.Create))
{
2014-05-25 12:09:49 +12:00
DownloadFile(remotePath, fs);
}
2013-11-03 23:53:49 +13:00
}
public void DownloadFiles(IEnumerable<FtpListItem> files, string localPath, bool recursive = true)
2013-11-03 23:53:49 +13:00
{
foreach (FtpListItem file in files)
2013-11-03 23:53:49 +13:00
{
if (file != null && !string.IsNullOrEmpty(file.Name))
{
if (recursive && file.Type == FtpObjectType.Directory)
2013-11-03 23:53:49 +13:00
{
2014-05-25 16:39:13 +12:00
FtpListItem[] newFiles = GetListing(file.FullName);
2013-11-03 23:53:49 +13:00
string directoryPath = Path.Combine(localPath, file.Name);
2013-11-03 23:53:49 +13:00
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
DownloadFiles(newFiles, directoryPath);
}
else if (file.Type == FtpObjectType.File)
2013-11-03 23:53:49 +13:00
{
string filePath = Path.Combine(localPath, file.Name);
DownloadFile(file.FullName, filePath);
2013-11-03 23:53:49 +13:00
}
}
}
}
2014-05-25 16:39:13 +12:00
public FtpListItem[] GetListing(string remotePath)
{
return client.GetListing(remotePath);
}
2014-05-31 02:59:08 +12:00
public bool DirectoryExists(string remotePath)
2013-11-03 23:53:49 +13:00
{
if (Connect())
{
2014-05-31 02:59:08 +12:00
return client.DirectoryExists(remotePath);
2013-11-03 23:53:49 +13:00
}
return false;
}
2014-05-31 02:59:08 +12:00
public bool CreateDirectory(string remotePath)
2013-11-03 23:53:49 +13:00
{
if (Connect())
{
try
{
client.CreateDirectory(remotePath);
2013-11-03 23:53:49 +13:00
return true;
}
catch (Exception e)
{
DebugHelper.WriteException(e);
}
}
return false;
}
2014-05-31 02:59:08 +12:00
public List<string> CreateMultiDirectory(string remotePath)
2013-11-03 23:53:49 +13:00
{
List<string> paths = URLHelpers.GetPaths(remotePath);
2013-11-03 23:53:49 +13:00
foreach (string path in paths)
{
2014-05-31 02:59:08 +12:00
if (CreateDirectory(path))
2013-11-03 23:53:49 +13:00
{
DebugHelper.WriteLine($"FTP directory created: {path}");
2013-11-03 23:53:49 +13:00
}
}
2014-05-31 02:59:08 +12:00
return paths;
2013-11-03 23:53:49 +13:00
}
public void Rename(string fromRemotePath, string toRemotePath)
{
2014-05-25 12:09:49 +12:00
if (Connect())
{
client.Rename(fromRemotePath, toRemotePath);
}
2013-11-03 23:53:49 +13:00
}
public void DeleteFile(string remotePath)
{
2014-05-25 12:09:49 +12:00
if (Connect())
{
client.DeleteFile(remotePath);
}
2013-11-03 23:53:49 +13:00
}
public void DeleteFiles(IEnumerable<FtpListItem> files)
2013-11-03 23:53:49 +13:00
{
foreach (FtpListItem file in files)
2013-11-03 23:53:49 +13:00
{
if (file != null && !string.IsNullOrEmpty(file.Name))
{
if (file.Type == FtpObjectType.Directory)
2013-11-03 23:53:49 +13:00
{
DeleteDirectory(file.FullName);
2013-11-03 23:53:49 +13:00
}
else if (file.Type == FtpObjectType.File)
2013-11-03 23:53:49 +13:00
{
DeleteFile(file.FullName);
2013-11-03 23:53:49 +13:00
}
}
}
}
public void DeleteDirectory(string remotePath)
{
2014-05-25 12:09:49 +12:00
if (Connect())
2013-11-03 23:53:49 +13:00
{
2021-12-12 10:21:19 +13:00
string fileName = URLHelpers.GetFileName(remotePath);
if (fileName == "." || fileName == "..")
2014-05-25 12:09:49 +12:00
{
return;
}
2013-11-03 23:53:49 +13:00
2014-05-25 16:39:13 +12:00
FtpListItem[] files = GetListing(remotePath);
2013-11-03 23:53:49 +13:00
2014-05-25 12:09:49 +12:00
DeleteFiles(files);
2013-11-03 23:53:49 +13:00
2014-05-25 12:09:49 +12:00
client.DeleteDirectory(remotePath);
}
2013-11-03 23:53:49 +13:00
}
public bool SendCommand(string command)
{
2014-05-25 12:09:49 +12:00
if (Connect())
2013-11-03 23:53:49 +13:00
{
2014-05-25 12:09:49 +12:00
try
{
client.Execute(command);
return true;
}
catch (Exception e)
{
DebugHelper.WriteException(e);
}
2013-11-03 23:53:49 +13:00
}
2014-05-25 12:09:49 +12:00
return false;
2013-11-03 23:53:49 +13:00
}
public void Dispose()
{
if (client != null)
{
try
{
client.Dispose();
}
catch (Exception e)
{
DebugHelper.WriteException(e);
}
}
2013-11-03 23:53:49 +13:00
}
}
}