#region License Information (GPL v3) /* ShareX - A program that allows you to take screenshots and share any file type Copyright (C) 2007-2014 ShareX Developers 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 . */ #endregion License Information (GPL v3) using HelpersLib; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Net; using System.Net.FtpClient; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; namespace UploadersLib.FileUploaders { public sealed class FTP : FileUploader, IDisposable { public FTPAccount Account { get; private set; } private FtpClient client; public FTP(FTPAccount account) { Account = account; client = new FtpClient() { Host = Account.Host, Port = Account.Port, Credentials = new NetworkCredential(Account.Username, Account.Password) }; if (account.IsActive) { client.DataConnectionType = FtpDataConnectionType.AutoActive; } else { client.DataConnectionType = FtpDataConnectionType.AutoPassive; } if (account.Protocol == FTPProtocol.FTPS) { switch (Account.FTPSEncryption) { default: case FTPSEncryption.Explicit: client.EncryptionMode = FtpEncryptionMode.Explicit; break; case FTPSEncryption.Implicit: client.EncryptionMode = FtpEncryptionMode.Implicit; break; } client.DataConnectionEncryption = true; if (!string.IsNullOrEmpty(account.FTPSCertificateLocation) && File.Exists(account.FTPSCertificateLocation)) { X509Certificate cert = X509Certificate2.CreateFromSignedFile(Account.FTPSCertificateLocation); client.ClientCertificates.Add(cert); } else { client.ValidateCertificate += (FtpClient control, FtpSslValidationEventArgs e) => { if (e.PolicyErrors != SslPolicyErrors.None) { e.Accept = true; } }; } } } public override UploadResult Upload(Stream stream, string fileName) { UploadResult result = new UploadResult(); fileName = Helpers.GetValidURL(fileName); string path = Account.GetSubFolderPath(fileName); try { IsUploading = true; UploadData(stream, path); } finally { IsUploading = false; } if (!stopUpload && Errors.Count == 0) { result.URL = Account.GetUriPath(fileName); } return result; } public override void StopUpload() { if (IsUploading && !stopUpload) { stopUpload = true; Disconnect(); } } public bool Connect() { if (!client.IsConnected) { client.Connect(); } return client.IsConnected; } public void Disconnect() { if (client != null && client.IsConnected) { client.Disconnect(); } } public bool UploadData(Stream localStream, string remotePath) { if (Connect()) { try { using (Stream remoteStream = client.OpenWrite(remotePath)) { return TransferData(localStream, remoteStream); } } catch (FtpCommandException e) { // Probably directory not exist, try creating it if (e.CompletionCode == "553") { MakeMultiDirectory(FTPHelpers.GetDirectoryName(remotePath)); using (Stream remoteStream = client.OpenWrite(remotePath)) { return TransferData(localStream, remoteStream); } } throw e; } } return false; } 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)) { string filename = Path.GetFileName(file); if (File.Exists(file)) { UploadFile(file, Helpers.CombineURL(remotePath, filename)); } else if (Directory.Exists(file)) { List filesList = new List(); filesList.AddRange(Directory.GetFiles(file)); filesList.AddRange(Directory.GetDirectories(file)); string path = Helpers.CombineURL(remotePath, filename); MakeDirectory(path); UploadFiles(filesList.ToArray(), path); } } } } public void DownloadFile(string remotePath, Stream localStream) { if (Connect()) { using (Stream remoteStream = client.OpenRead(remotePath)) { TransferData(remoteStream, localStream); } } } public void DownloadFile(string remotePath, string localPath) { using (FileStream fs = new FileStream(localPath, FileMode.Create)) { DownloadFile(remotePath, fs); } } public void DownloadFiles(IEnumerable files, string localPath, bool recursive = true) { foreach (FtpListItem file in files) { if (file != null && !string.IsNullOrEmpty(file.Name)) { if (recursive && file.Type == FtpFileSystemObjectType.Directory) { FtpListItem[] newFiles = GetListing(file.FullName); string directoryPath = Path.Combine(localPath, file.Name); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } DownloadFiles(newFiles, directoryPath); } else if (file.Type == FtpFileSystemObjectType.File) { string filePath = Path.Combine(localPath, file.Name); DownloadFile(file.FullName, filePath); } } } } public FtpListItem[] GetListing(string remotePath) { return client.GetListing(remotePath); } public bool ChangeDirectory(string remotePath, bool autoCreateDirectory = false) { if (Connect()) { remotePath = FTPHelpers.AddSlash(remotePath, FTPHelpers.SlashType.Prefix); try { client.SetWorkingDirectory(remotePath); return true; } catch (FtpCommandException e) { // Probably directory not exist, try creating it if (e.CompletionCode == "550" && autoCreateDirectory) { MakeMultiDirectory(remotePath); client.SetWorkingDirectory(remotePath); return true; } throw e; } } return false; } public bool MakeDirectory(string remotePath) { if (Connect()) { try { client.CreateDirectory(remotePath); return true; } catch (Exception e) { DebugHelper.WriteException(e); } } return false; } public void MakeMultiDirectory(string remotePath) { List paths = FTPHelpers.GetPaths(remotePath); foreach (string path in paths) { if (MakeDirectory(path)) { DebugHelper.WriteLine("FTP directory created: " + path); } } } public void Rename(string fromRemotePath, string toRemotePath) { if (Connect()) { client.Rename(fromRemotePath, toRemotePath); } } public void DeleteFile(string remotePath) { if (Connect()) { client.DeleteFile(remotePath); } } public void DeleteFiles(IEnumerable files) { foreach (FtpListItem file in files) { if (file != null && !string.IsNullOrEmpty(file.Name)) { if (file.Type == FtpFileSystemObjectType.Directory) { DeleteDirectory(file.FullName); } else if (file.Type == FtpFileSystemObjectType.File) { DeleteFile(file.FullName); } } } } public void DeleteDirectory(string remotePath) { if (Connect()) { string filename = FTPHelpers.GetFileName(remotePath); if (filename == "." || filename == "..") { return; } FtpListItem[] files = GetListing(remotePath); DeleteFiles(files); client.DeleteDirectory(remotePath); } } public bool SendCommand(string command) { if (Connect()) { try { client.Execute(command); return true; } catch (Exception e) { DebugHelper.WriteException(e); } } return false; } public void Dispose() { if (client != null) { Disconnect(); client.Dispose(); } } } }