//******************************************************************************************************
// FtpClient.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 05/22/2003 - J. Ritchie Carroll
// Generated original version of source code.
// 09/23/2008 - J. Ritchie Carroll
// Generated original version of source code.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/17/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
#region [ Contributor License Agreements ]
//*******************************************************************************************************
//
// Code based on the following project:
// http://www.codeproject.com/KB/IP/net_ftp_upload.aspx
//
// Copyright Alex Kwok & Uwe Keim
//
// The Code Project Open License (CPOL):
// http://www.codeproject.com/info/cpol10.aspx
//
//*******************************************************************************************************
#endregion
using System;
using System.ComponentModel;
using System.Drawing;
using System.Net;
// This FTP library is based on a similar C# library found on "The Code Project" web site originally written by
// Alex Kwok (no license specified), then enhanced by Uwe Keim (licensed under The Code Project Open License).
// GSF translated the code into VB with most of classes being renamed (removed Ftp prefix) and the namespace was
// changed to GSF.Ftp. Many fixes, additions and modifications have been made to this code as well as extensive
// testing. Note worthy changes: converted the C# delegates to standard .NET events for ease of use, made the
// library work with IIS based FTP servers that were in Unix mode, added detailed file system information for FTP
// files and directories (size, timestamp, etc), converted FTP session into a component that could be dragged onto
// a design surface, created an FTP FileWatcher component and an FTP file system crawler based on this library.
// In 2008 we migrated the entire code set to C# and restored the original "Ftp" prefix to the classes for to
// satisfy uniqueness in type name constraint coming from code analysis.
namespace GSF.Net.Ftp
{
///
/// Represents a FTP session.
///
///
/// Creates a client connection to an FTP server for uploading or downloading files.
///
[ToolboxBitmap(typeof(FtpClient)), DefaultProperty("Server"), DefaultEvent("FileTransferProgress"), Description("Creates a client connection to an FTP server")]
public class FtpClient : Component
{
#region [ Members ]
// Events
///
/// Raised when file transfer begins.
///
///
/// is local filename,
/// is remote filename,
/// is file transfer direction.
///
public event EventHandler> BeginFileTransfer;
///
/// Raised when file transfer completes.
///
///
/// is local filename,
/// is remote filename,
/// is file transfer direction.
///
public event EventHandler> EndFileTransfer;
///
/// Raised as file transfer is progressing.
///
///
/// is current file transfer progress,
/// is file transfer direction.
///
public event EventHandler, TransferDirection>> FileTransferProgress;
///
/// Raised when asynchronous file transfer process has completed (success or failure).
///
///
/// is result of asynchronous FTP transfer process.
///
public event EventHandler> FileTransferNotification;
///
/// Raised when FTP response has been received.
///
///
/// is received FTP response.
///
public event EventHandler> ResponseReceived;
///
/// Raised when FTP command has been sent.
///
///
/// is sent FTP command.
///
public event EventHandler> CommandSent;
// Fields
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Constructs a new FTP session using the default settings.
///
public FtpClient()
: this(false)
{
}
///
/// Constructs a new FTP session using the specified settings.
///
/// Set to true to not be case sensitive with FTP file and directory names.
public FtpClient(bool caseInsensitive)
{
CaseInsensitive = caseInsensitive;
WaitLockTimeout = 10;
State = new FtpSessionDisconnected(this, CaseInsensitive);
}
///
/// Initializes a new instance of the class.
///
/// object that contains the .
public FtpClient(IContainer container)
: this()
{
container?.Add(this);
}
#endregion
#region [ Properties ]
///
/// Gets or sets FTP server name (DNS name or IP).
///
///
/// FTP server name should not be prefixed with FTP://.
///
[Browsable(true), Category("Configuration"), Description("Specify FTP server name (do not prefix with FTP://).")]
public string Server
{
get => State.Server;
set => State.Server = value;
}
///
/// Gets or sets FTP case sensitivity of file and directory names.
///
///
/// Set to true to not be case sensitive with FTP file and directory names.
///
[Browsable(true), Category("Configuration"), Description("Set to True to not be case sensitive with FTP file names."), DefaultValue(false)]
public bool CaseInsensitive { get; set; }
///
/// Gets or sets FTP server port to use, defaults to 21.
///
///
/// This only needs to be changed if the FTP server is established on a non-standard port number.
///
[Browsable(true), Category("Configuration"), Description("Specify FTP server port, if needed."), DefaultValue(21)]
public int Port
{
get => State.Port;
set => State.Port = value;
}
///
/// Gets or sets the timeout, in milliseconds, for
/// read and write operations, defaults to 30 seconds.
///
[Browsable(true), Category("Configuration"), Description("Specify FTP server read/write timeout, if needed."), DefaultValue(30000)]
public int Timeout
{
get => State.Timeout;
set => State.Timeout = value;
}
///
/// Gets or sets the passive/active mode of the server.
///
[Browsable(true), Category("Configuration"), Description("Specify passive/active mode of FTP server."), DefaultValue(true)]
public bool Passive
{
get => State.Passive;
set => State.Passive = value;
}
///
/// Gets or sets the IP address to send with the PORT command.
///
[Browsable(true), Category("Configuration"), Description("Specify IP address to send with PORT command."), DefaultValue(null)]
public string ActiveAddress
{
get => State.ActiveAddress.ToString();
set => State.ActiveAddress = IPAddress.TryParse(value, out IPAddress address) ? address : null;
}
///
/// Gets or sets the minimum value in the range of ports
/// used when listening for connections in active mode.
///
[Browsable(true), Category("Configuration"), Description("Specify minimum port in range of active ports."), DefaultValue(0)]
public int MinActivePort
{
get => State.MinActivePort;
set => State.MinActivePort = value;
}
///
/// Gets or sets the maximum value in the range of ports
/// used when listening for connections in active mode.
///
[Browsable(true), Category("Configuration"), Description("Specify maximum port in range of active ports."), DefaultValue(0)]
public int MaxActivePort
{
get => State.MaxActivePort;
set => State.MaxActivePort = value;
}
///
/// Gets or sets current FTP session directory.
///
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public FtpDirectory CurrentDirectory
{
get => State.CurrentDirectory;
set => State.CurrentDirectory = value;
}
///
/// Gets FTP session root directory entry.
///
[Browsable(false)]
public FtpDirectory RootDirectory => State.RootDirectory;
///
/// Gets or sets maximum number of seconds to wait for read lock for files to be uploaded. Defaults to 10 seconds.
///
[Browsable(true), Category("Configuration"), Description("Specify the maximum number of seconds to wait for read lock for files to be uploaded."), DefaultValue(10)]
public int WaitLockTimeout { get; set; }
///
/// Changes the current FTP session directory to the specified path.
///
/// New directory.
public void SetCurrentDirectory(string directoryPath)
{
if (!IsConnected)
throw new InvalidOperationException("You must be connected to the FTP server before you can set the current directory.");
if (directoryPath.Length <= 0)
return;
State.CurrentDirectory = new FtpDirectory((FtpSessionConnected)State, CaseInsensitive, directoryPath);
State.CurrentDirectory.Refresh();
}
///
/// Gets the current FTP control channel.
///
[Browsable(false)]
public FtpControlChannel ControlChannel => State.ControlChannel;
///
/// Returns true if FTP session is currently connected.
///
[Browsable(false)]
public bool IsConnected => State is FtpSessionConnected;
///
/// Returns true if FTP session is currently busy.
///
[Browsable(false)]
public bool IsBusy => State.IsBusy;
internal IFtpSessionState State { get; set; }
#endregion
#region [ Methods ]
///
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (m_disposed)
return;
try
{
if (!disposing)
return;
State?.Dispose();
State = null;
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
base.Dispose(disposing); // Call base class Dispose().
}
}
///
/// Aborts current file transfer.
///
public void AbortTransfer()
{
State.AbortTransfer();
}
///
/// Connects to FTP server using specified credentials.
///
/// User name used to authenticate to FTP server.
/// Password used to authenticate to FTP server.
public void Connect(string userName, string password)
{
State.Connect(userName, password);
}
///
/// Closes current FTP session.
///
public void Close()
{
State.Close();
}
internal void OnResponseReceived(string response)
{
ResponseReceived?.Invoke(this, new EventArgs(response));
}
internal void OnCommandSent(string command)
{
CommandSent?.Invoke(this, new EventArgs(command));
}
internal void OnBeginFileTransfer(string localFileName, string remoteFileName, TransferDirection transferDirection)
{
BeginFileTransfer?.Invoke(this, new EventArgs(localFileName, remoteFileName, transferDirection));
}
internal void OnEndFileTransfer(string localFileName, string remoteFileName, TransferDirection transferDirection)
{
EndFileTransfer?.Invoke(this, new EventArgs(localFileName, remoteFileName, transferDirection));
}
internal void OnFileTransferProgress(ProcessProgress fileTransferProgress, TransferDirection transferDirection)
{
FileTransferProgress?.Invoke(this, new EventArgs, TransferDirection>(fileTransferProgress, transferDirection));
}
internal void OnFileTransferNotification(FtpAsyncResult transferResult)
{
FileTransferNotification?.Invoke(this, new EventArgs(transferResult));
}
#endregion
}
}