//  
//   Rebex Sample Code License
// 
//   Copyright 2026, REBEX CR s.r.o.
//   All rights reserved.
//   https://www.rebex.net/
// 
//   Permission to use, copy, modify, and/or distribute this software for any
//   purpose with or without fee is hereby granted.
// 
//   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.
// 

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Resources;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

using Rebex.IO;
using Rebex.Net;
using Rebex.Security.Certificates;

namespace Rebex.Samples
{
    /// <summary>
    /// very simple ftp client
    /// </summary>
    public class MainForm : System.Windows.Forms.Form
    {

        private System.ComponentModel.Container components = null;
        private System.Windows.Forms.RichTextBox tbLog;
        private System.Windows.Forms.ListView listServer;
        private System.Windows.Forms.ColumnHeader name;
        private System.Windows.Forms.ColumnHeader size;
        private System.Windows.Forms.Label lblServer;
        private System.Windows.Forms.ListView listLocal;
        private System.Windows.Forms.Label lblLocal;
        private System.Windows.Forms.Label lblServerDirectory;
        private System.Windows.Forms.ColumnHeader columnHeader1;
        private System.Windows.Forms.ColumnHeader columnHeader2;
        private System.Windows.Forms.Label lblLocalDirectory;
        private System.Windows.Forms.ColumnHeader date;
        private System.Windows.Forms.ColumnHeader columnHeader3;
        private System.Windows.Forms.Button btnStop;
        private System.Windows.Forms.Button btnDelete;
        private System.Windows.Forms.Button btnUpload;
        private System.Windows.Forms.Button btnDownload;
        private System.Windows.Forms.RadioButton rbBin;
        private System.Windows.Forms.RadioButton rbAsc;
        private System.Windows.Forms.Button btnRefresh;
        private System.Windows.Forms.Button btnMakeDir;
        private System.Windows.Forms.ComboBox cbDrives;
        private System.Windows.Forms.Button btnConnect;
        private System.Windows.Forms.GroupBox gbControl;
        private System.Windows.Forms.GroupBox gbTransfer;
        private System.Windows.Forms.PictureBox headerLeft;
        private System.Windows.Forms.Panel headerMiddle;
        private System.Windows.Forms.PictureBox headerRight;
        private System.Windows.Forms.TrackBar trackBar;
        private System.Windows.Forms.Label lblSpeed;
        private System.Windows.Forms.Button btnErrorWarning;
        private System.Windows.Forms.CheckBox cbModeZ;
        private System.Windows.Forms.PictureBox pbSecure;
        private System.Windows.Forms.CheckBox cbST;
        private System.Windows.Forms.StatusStrip mainStatusStrip;
        private System.Windows.Forms.ToolStripProgressBar pbTransfer;
        private System.Windows.Forms.ToolStripStatusLabel lblProgress;
        private System.Windows.Forms.SplitContainer mainSplitContainer;
        private System.Windows.Forms.TableLayoutPanel tableLayout;
        private System.Windows.Forms.Panel panelMiddle;
        private System.Windows.Forms.Panel panelLeft;
        private System.Windows.Forms.Panel panelRight;

        private Ftp _ftp;                           // FTP session
        private ListView listActive;                // active list (server x local)
        private int _serverDirs;                    // number of dirs on server side
        private int _localDirs;                     // number of dirs on local side
        private int _selectedDrive = -1;            // selected drive (A:, C:, ...) in combo
        private string _localPath;                  // local path
        private bool _isWorking;                    // determines whether any operation is running
        private DateTime _transferTime;             // transfer launch-time
        private bool _cccMode = false;              // clear command channel enabled?
        private ProblemDetectedForm _problemForm;   // informs the user about problems while transferring data

        // constansts
        private const string SYMLINK = "--->";      // symlink tag
        private const string URL = "https://www.rebex.net/ftp-ssl.net/"; // url
        private string _exception = "";			  // last occured exception

        public void WriteToLog(Exception x)
        {
            if (x is AggregateException)
            {
                foreach (Exception inner in ((AggregateException)x).InnerExceptions)
                {
                    WriteToLog(inner);
                }
                return;
            }

            ShowErrorWarning(x.ToString());

            // FtpExceptions are automatilcally logged by component logger.
            // No need to display them again.
            // We don't wont duplicate entries for such exceptions.
            if (x is FtpException)
                return;

            WriteToLog("* " + x.ToString(), RichTextBoxLogWriter.COLORERROR);
        }

        public void ShowErrorWarning(string message)
        {
            _exception = message;
            btnErrorWarning.Visible = true;
        }

        public void WriteToLog(string message, Color color)
        {
            tbLog.Focus();
            tbLog.SelectionColor = color;
            tbLog.AppendText(message + "\r\n");
        }


        /// <summary>
        /// format datetime to readable form in the panels
        /// </summary>
        /// <param name="dt">datetime</param>
        /// <returns>formatted string</returns>
        private static string FormatFileTime(DateTime dt)
        {
            return dt.ToString("yyyy-MM-dd HH:mm");
        }

        /// <summary>
        /// Converts transfer mode selected in connection form into SSL mode.
        /// </summary>
        /// <param name="transferMode">Selected transfer mode.</param>
        /// <returns>Converted SSL mode.</returns>
        private static SslMode ConvertToSslMode(FileTransferMode transferMode)
        {
            switch (transferMode)
            {
                case FileTransferMode.FtpSslExplicit:
                    return SslMode.Explicit;
                case FileTransferMode.FtpSslImplicit:
                    return SslMode.Implicit;
            }

            return SslMode.None;
        }

        /// <summary>
        /// event displaying ftp state
        /// </summary>
        private void StateChanged(object sender, FtpStateChangedEventArgs e)
        {
            switch (e.NewState)
            {
                case FtpState.Disconnected:
                case FtpState.Disposed:
                    pbSecure.Visible = false;
                    lblProgress.Text = "Disconnected";
                    btnConnect.Text = "Connect...";
                    listServer.Items.Clear();
                    break;
                case FtpState.Ready:
                    lblProgress.Text = "Ready";
                    break;
            }
        }

        /// <summary>
        /// handles the displaying traversing event
        /// </summary>
        void Traversing(object sender, FtpTraversingEventArgs e)
        {
            if (e.Action == TransferAction.Listing)
                return;

            string strBatchInfo = string.Format("({0} file{1} traversed)    ",
                e.FilesTotal, (e.FilesTotal > 1 ? "s" : null));

            switch (e.TraversingState)
            {
                case TraversingState.DirectoryRetrieved:
                    strBatchInfo += "Directory retrieved.";
                    break;
                case TraversingState.DirectoryRetrieving:
                    strBatchInfo += "Retrieving directory...";
                    break;
                case TraversingState.HierarchyRetrieved:
                    strBatchInfo += string.Format("Hierarchy retrieved ({0} byte{1} in {2} file{3}).",
                        e.BytesTotal, (e.BytesTotal > 1 ? "s" : null),
                        e.FilesTotal, (e.FilesTotal > 1 ? "s" : null));
                    break;
                case TraversingState.HierarchyRetrieving:
                    strBatchInfo += "Retrieving hierarchy...";
                    break;
            }

            lblProgress.Text = strBatchInfo;
        }

        /// <summary>
        /// handles the transfer progress changed event
        /// </summary>
        void TransferProgressChanged(object sender, FtpTransferProgressChangedEventArgs e)
        {
            string strBatchInfo = string.Format("({0} / {1} file{2} processed)    ",
                e.FilesProcessed, e.FilesTotal, (e.FilesProcessed > 1 ? "s" : null));

            SetProgressValue(Convert.ToInt32(e.ProgressPercentage));

            switch (e.TransferState)
            {
                case TransferProgressState.DataBlockProcessed:
                    strBatchInfo += e.BytesTransferred + " bytes";
                    break;
                case TransferProgressState.DirectoryProcessing:
                    strBatchInfo += "Processing directory...";
                    break;
                case TransferProgressState.FileTransferring:
                    strBatchInfo += "Transferring file...";
                    break;
                case TransferProgressState.FileTransferred:
                    strBatchInfo += "File transferred.";
                    break;
                case TransferProgressState.TransferCompleted:
                    strBatchInfo += "Transfer completed.";
                    ShowTransferStatus(e.BytesTransferred, e.FilesTransferred);
                    break;
            }

            lblProgress.Text = strBatchInfo;
        }

        private void SetProgressValue(int value)
        {
            // workaround for progress bar smoothing
            if (value == 100)
            {
                pbTransfer.Maximum = 101;
                pbTransfer.Value = 101;
                pbTransfer.Maximum = 100;
                System.Threading.Thread.Sleep(200);
            }
            else
            {
                pbTransfer.Value = value;
            }
        }

        /// <summary>
        /// handles the delete progress changed event
        /// </summary>
        private void DeleteProgressChanged(object sender, FtpDeleteProgressChangedEventArgs e)
        {
            string strDeleteInfo = string.Format("({0} / {1} file{2} deleted)    ",
                e.FilesProcessed, e.FilesTotal, (e.FilesProcessed > 1 ? "s" : null));

            switch (e.DeleteState)
            {
                case DeleteProgressState.DeleteCompleted:
                    strDeleteInfo += "Delete completed.";
                    break;
                case DeleteProgressState.DirectoryDeleted:
                    strDeleteInfo += "Directory deleted.";
                    break;
                case DeleteProgressState.DirectoryProcessing:
                    strDeleteInfo += "Processing directory...";
                    break;
                case DeleteProgressState.FileDeleted:
                    strDeleteInfo += "File deleted.";
                    break;
                case DeleteProgressState.FileDeleting:
                    strDeleteInfo += "Deleting file...";
                    break;
            }

            lblProgress.Text = strDeleteInfo;
        }

        /// <summary>
        /// handles the batch transfer problem detected event
        /// </summary>
        private void ProblemDetected(object sender, FtpProblemDetectedEventArgs e)
        {
            _problemForm.ShowModal(this, e);
        }

        /// <summary>
        /// make local list + drives combo box
        /// </summary>
        public void MakeLocalList()
        {
            int dirs = 0;
            int files = 0;
            long size = 0;

            // make a logical drives list [first run only]

            if (cbDrives.Items.Count <= 0)
            {
                string[] drives = Directory.GetLogicalDrives();
                string lowerDrive = @"c:\";

                // find "lower" acceptable drive

                for (int c = drives.Length - 1; c >= 0; c--)
                {
                    if (drives[c].ToLower().CompareTo(@"c:\") >= 0)
                        lowerDrive = drives[c].ToLower();
                }

                // feed the drives' list and select one

                for (int c = 0; c < drives.Length; c++)
                {
                    string drive = drives[c];

                    cbDrives.Items.Add(drive);

                    if (_selectedDrive == -1 && drive.ToLower().CompareTo(lowerDrive) == 0)
                    {
                        cbDrives.SelectedIndex = c;
                        _selectedDrive = c;
                    }
                }

                if (cbDrives.SelectedIndex <= 0)
                    cbDrives.SelectedIndex = 0;
            }

            // create the list
            listLocal.Items.Clear();

            // directory up
            if (_localPath != null && _localPath.Length > 3)
            {
                listLocal.Items.Add(new ListViewItem("..", 0));
                dirs++;
            }
            else
            {
                _localPath = cbDrives.SelectedItem.ToString();
            }

            DirectoryInfo directory = new DirectoryInfo(_localPath);
            DirectoryInfo[] list = directory.GetDirectories();

            for (int c = 0; c < list.Length; c++)
            {
                string[] row = new string[3];
                row[0] = list[c].Name;
                row[1] = "";

                // time [on read-only devices LWT is not available for dirs?]

                try
                {
                    row[2] = FormatFileTime(list[c].LastWriteTime);
                }
                catch
                {
                    row[2] = "";
                }

                listLocal.Items.Add(new ListViewItem(row, 1 + c));
                dirs++;
            }

            _localDirs = dirs;

            // files

            FileInfo[] list2 = directory.GetFiles();

            for (int c = 0; c < list2.Length; c++)
            {
                string[] row = new string[3];
                row[0] = list2[c].Name;
                row[1] = list2[c].Length.ToString();
                row[2] = FormatFileTime(list2[c].LastWriteTime);

                listLocal.Items.Add(new ListViewItem(row, 1 + dirs + files));
                size += list2[c].Length;
                files++;
            }

            // stats

            lblLocal.Text = dirs + " folder" + (dirs > 1 ? "s" : "") + ", " +
                files + " file" + (files > 1 ? "s" : "") + ", " +
                size / 1024 + " K";

            // working directory

            lblLocalDirectory.Text = directory.FullName;
            _localPath = directory.FullName;
        }

        /// <summary>
        /// make ftp list
        /// </summary>
        public async void MakeFtpList()
        {
            int dirs = 0;
            int files = 0;
            long size = 0;

            listServer.Items.Clear();

            // not connected?

            if (_ftp == null)
            {
                lblServerDirectory.Text = "";
                lblServer.Text = "";
                _serverDirs = 0;
                return;
            }
            // secure transfers

            if (cbST.Enabled && !_cccMode)
                _ftp.SecureTransfers = cbST.Checked;
            // make the list

            FtpItemCollection list = null;

            try
            {
                _isWorking = true;
                btnStop.Visible = true;

                list = await _ftp.GetListAsync();

                list.Sort();
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
                listServer.Items.Add(new ListViewItem("..", 0));
                return;
            }
            finally
            {
                btnStop.Visible = false;
                _isWorking = false;
            }

            // directories

            listServer.Items.Add(new ListViewItem("..", 0));
            dirs++;

            for (int c = 0; c < list.Count; c++)
            {
                string[] row = new string[3];
                row[0] = list[c].Name;
                row[1] = null;
                row[2] = FormatFileTime(list[c].LastWriteTime.Value);

                if (list[c].IsLink)
                {
                    row[1] = SYMLINK;
                }
                else if (list[c].IsFile)
                {
                    row[1] = list[c].Length.ToString();
                    size += list[c].Length;
                    files++;
                }
                else if (list[c].IsDirectory)
                {
                    dirs++;
                }

                ListViewItem lvi = new ListViewItem(row);
                lvi.Tag = list[c];
                listServer.Items.Add(lvi);

            }

            listServer.ListViewItemSorter = new ListViewColumnSorter();
            listServer.Sort();

            // stats
            lblServer.Text = dirs + " folder" + (dirs > 1 ? "s" : "") + ", " +
                files + " file" + (files > 1 ? "s" : "") + ", " +
                size / 1024 + " K";

            // working directory
            lblServerDirectory.Text = _ftp.GetCurrentDirectory();

            _serverDirs = dirs;
        }

        /// <summary>
        /// constructor
        /// </summary>
        public MainForm()
        {
            Application.EnableVisualStyles();
            CheckForIllegalCrossThreadCalls = true;
            InitializeComponent();

            rbBin.Checked = true;
            trackBar.Enabled = false;
            btnErrorWarning.Visible = false;
            lblServer.Text = "";
            listLocal.Focus();
            btnConnect.Select();

            MakeLocalList();
            _problemForm = new ProblemDetectedForm();

            WriteToLog("Welcome to Rebex FTP!", Color.DarkGreen);
        }

        /// <summary>
        /// clean up any resources being used
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            this.listServer = new System.Windows.Forms.ListView();
            this.name = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.size = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.date = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.listLocal = new System.Windows.Forms.ListView();
            this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.tbLog = new System.Windows.Forms.RichTextBox();
            this.lblServer = new System.Windows.Forms.Label();
            this.lblServerDirectory = new System.Windows.Forms.Label();
            this.lblLocal = new System.Windows.Forms.Label();
            this.lblLocalDirectory = new System.Windows.Forms.Label();
            this.btnStop = new System.Windows.Forms.Button();
            this.btnDelete = new System.Windows.Forms.Button();
            this.btnUpload = new System.Windows.Forms.Button();
            this.btnDownload = new System.Windows.Forms.Button();
            this.rbBin = new System.Windows.Forms.RadioButton();
            this.rbAsc = new System.Windows.Forms.RadioButton();
            this.btnRefresh = new System.Windows.Forms.Button();
            this.btnMakeDir = new System.Windows.Forms.Button();
            this.cbDrives = new System.Windows.Forms.ComboBox();
            this.btnConnect = new System.Windows.Forms.Button();
            this.gbControl = new System.Windows.Forms.GroupBox();
            this.gbTransfer = new System.Windows.Forms.GroupBox();
            this.cbModeZ = new System.Windows.Forms.CheckBox();
            this.cbST = new System.Windows.Forms.CheckBox();
            this.pbSecure = new System.Windows.Forms.PictureBox();
            this.headerLeft = new System.Windows.Forms.PictureBox();
            this.headerRight = new System.Windows.Forms.PictureBox();
            this.btnErrorWarning = new System.Windows.Forms.Button();
            this.trackBar = new System.Windows.Forms.TrackBar();
            this.lblSpeed = new System.Windows.Forms.Label();
            this.headerMiddle = new System.Windows.Forms.Panel();
            this.mainStatusStrip = new System.Windows.Forms.StatusStrip();
            this.pbTransfer = new System.Windows.Forms.ToolStripProgressBar();
            this.lblProgress = new System.Windows.Forms.ToolStripStatusLabel();
            this.mainSplitContainer = new System.Windows.Forms.SplitContainer();
            this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
            this.panelMiddle = new System.Windows.Forms.Panel();
            this.panelLeft = new System.Windows.Forms.Panel();
            this.panelRight = new System.Windows.Forms.Panel();
            this.gbControl.SuspendLayout();
            this.gbTransfer.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pbSecure)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.headerLeft)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.headerRight)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit();
            this.headerMiddle.SuspendLayout();
            this.mainStatusStrip.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.mainSplitContainer)).BeginInit();
            this.mainSplitContainer.Panel1.SuspendLayout();
            this.mainSplitContainer.Panel2.SuspendLayout();
            this.mainSplitContainer.SuspendLayout();
            this.tableLayout.SuspendLayout();
            this.panelMiddle.SuspendLayout();
            this.panelLeft.SuspendLayout();
            this.panelRight.SuspendLayout();
            this.SuspendLayout();
            // 
            // listServer
            // 
            this.listServer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.listServer.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.name,
            this.size,
            this.date});
            this.listServer.FullRowSelect = true;
            this.listServer.HideSelection = false;
            this.listServer.Location = new System.Drawing.Point(0, 16);
            this.listServer.MultiSelect = false;
            this.listServer.Name = "listServer";
            this.listServer.Size = new System.Drawing.Size(326, 397);
            this.listServer.TabIndex = 2;
            this.listServer.UseCompatibleStateImageBehavior = false;
            this.listServer.View = System.Windows.Forms.View.Details;
            this.listServer.DoubleClick += new System.EventHandler(this.listServer_DoubleClick);
            this.listServer.Enter += new System.EventHandler(this.listServer_Enter);
            this.listServer.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.listServer_KeyPress);
            // 
            // name
            // 
            this.name.Name = "name";
            this.name.Text = "Name";
            this.name.Width = 120;
            // 
            // size
            // 
            this.size.Name = "size";
            this.size.Text = "Size";
            this.size.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // date
            // 
            this.date.Name = "date";
            this.date.Text = "Date";
            this.date.Width = 120;
            // 
            // listLocal
            // 
            this.listLocal.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.listLocal.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.columnHeader1,
            this.columnHeader2,
            this.columnHeader3});
            this.listLocal.FullRowSelect = true;
            this.listLocal.HideSelection = false;
            this.listLocal.Location = new System.Drawing.Point(0, 16);
            this.listLocal.MultiSelect = false;
            this.listLocal.Name = "listLocal";
            this.listLocal.Size = new System.Drawing.Size(326, 437);
            this.listLocal.TabIndex = 25;
            this.listLocal.UseCompatibleStateImageBehavior = false;
            this.listLocal.View = System.Windows.Forms.View.Details;
            this.listLocal.DoubleClick += new System.EventHandler(this.listLocal_DoubleClick);
            this.listLocal.Enter += new System.EventHandler(this.listLocal_Enter);
            this.listLocal.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.listLocal_KeyPress);
            // 
            // columnHeader1
            // 
            this.columnHeader1.Name = "columnHeader1";
            this.columnHeader1.Text = "Name";
            this.columnHeader1.Width = 120;
            // 
            // columnHeader2
            // 
            this.columnHeader2.Name = "columnHeader2";
            this.columnHeader2.Text = "Size";
            this.columnHeader2.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
            // 
            // columnHeader3
            // 
            this.columnHeader3.Name = "columnHeader3";
            this.columnHeader3.Text = "Date";
            this.columnHeader3.Width = 120;
            // 
            // tbLog
            // 
            this.tbLog.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
            this.tbLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.tbLog.BackColor = System.Drawing.SystemColors.Control;
            this.tbLog.Cursor = System.Windows.Forms.Cursors.IBeam;
            this.tbLog.Font = new System.Drawing.Font("Lucida Console", 9F);
            this.tbLog.Location = new System.Drawing.Point(0, 0);
            this.tbLog.MaxLength = 1000000;
            this.tbLog.Name = "tbLog";
            this.tbLog.ReadOnly = true;
            this.tbLog.Size = new System.Drawing.Size(760, 110);
            this.tbLog.TabIndex = 8;
            this.tbLog.Text = "";
            this.tbLog.WordWrap = false;
            // 
            // lblServer
            // 
            this.lblServer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.lblServer.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F);
            this.lblServer.Location = new System.Drawing.Point(3, 419);
            this.lblServer.Name = "lblServer";
            this.lblServer.Size = new System.Drawing.Size(220, 20);
            this.lblServer.TabIndex = 9;
            this.lblServer.Text = "12345";
            // 
            // lblServerDirectory
            // 
            this.lblServerDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.lblServerDirectory.BackColor = System.Drawing.SystemColors.InactiveCaption;
            this.lblServerDirectory.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.lblServerDirectory.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold);
            this.lblServerDirectory.ForeColor = System.Drawing.SystemColors.InactiveCaptionText;
            this.lblServerDirectory.Location = new System.Drawing.Point(0, 0);
            this.lblServerDirectory.Name = "lblServerDirectory";
            this.lblServerDirectory.Size = new System.Drawing.Size(326, 16);
            this.lblServerDirectory.TabIndex = 1;
            this.lblServerDirectory.Text = "/root";
            this.lblServerDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            this.lblServerDirectory.Click += new System.EventHandler(this.listServer_Enter);
            // 
            // lblLocal
            // 
            this.lblLocal.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.lblLocal.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F);
            this.lblLocal.Location = new System.Drawing.Point(3, 457);
            this.lblLocal.Name = "lblLocal";
            this.lblLocal.Size = new System.Drawing.Size(323, 19);
            this.lblLocal.TabIndex = 12;
            this.lblLocal.Text = "12345";
            // 
            // lblLocalDirectory
            // 
            this.lblLocalDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.lblLocalDirectory.BackColor = System.Drawing.SystemColors.InactiveCaption;
            this.lblLocalDirectory.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.lblLocalDirectory.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold);
            this.lblLocalDirectory.ForeColor = System.Drawing.SystemColors.InactiveCaptionText;
            this.lblLocalDirectory.Location = new System.Drawing.Point(0, 0);
            this.lblLocalDirectory.Name = "lblLocalDirectory";
            this.lblLocalDirectory.Size = new System.Drawing.Size(326, 16);
            this.lblLocalDirectory.TabIndex = 23;
            this.lblLocalDirectory.Text = "/root";
            this.lblLocalDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            this.lblLocalDirectory.Click += new System.EventHandler(this.listLocal_Enter);
            // 
            // btnStop
            // 
            this.btnStop.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnStop.Location = new System.Drawing.Point(16, 225);
            this.btnStop.Name = "btnStop";
            this.btnStop.Size = new System.Drawing.Size(75, 23);
            this.btnStop.TabIndex = 17;
            this.btnStop.Text = "Abort";
            this.btnStop.Visible = false;
            this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
            // 
            // btnDelete
            // 
            this.btnDelete.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnDelete.Location = new System.Drawing.Point(16, 130);
            this.btnDelete.Name = "btnDelete";
            this.btnDelete.Size = new System.Drawing.Size(75, 23);
            this.btnDelete.TabIndex = 11;
            this.btnDelete.Text = "Delete";
            this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
            // 
            // btnUpload
            // 
            this.btnUpload.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnUpload.Location = new System.Drawing.Point(16, 196);
            this.btnUpload.Name = "btnUpload";
            this.btnUpload.Size = new System.Drawing.Size(75, 23);
            this.btnUpload.TabIndex = 15;
            this.btnUpload.Text = "< Upload";
            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
            // 
            // btnDownload
            // 
            this.btnDownload.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnDownload.Location = new System.Drawing.Point(16, 167);
            this.btnDownload.Name = "btnDownload";
            this.btnDownload.Size = new System.Drawing.Size(75, 23);
            this.btnDownload.TabIndex = 13;
            this.btnDownload.Text = "Download >";
            this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click);
            // 
            // rbBin
            // 
            this.rbBin.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.rbBin.Location = new System.Drawing.Point(16, 16);
            this.rbBin.Name = "rbBin";
            this.rbBin.Size = new System.Drawing.Size(65, 20);
            this.rbBin.TabIndex = 19;
            this.rbBin.Text = "Binary";
            // 
            // rbAsc
            // 
            this.rbAsc.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.rbAsc.Location = new System.Drawing.Point(16, 37);
            this.rbAsc.Name = "rbAsc";
            this.rbAsc.Size = new System.Drawing.Size(68, 20);
            this.rbAsc.TabIndex = 21;
            this.rbAsc.Text = "ASCII";
            // 
            // btnRefresh
            // 
            this.btnRefresh.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnRefresh.Location = new System.Drawing.Point(16, 72);
            this.btnRefresh.Name = "btnRefresh";
            this.btnRefresh.Size = new System.Drawing.Size(75, 23);
            this.btnRefresh.TabIndex = 5;
            this.btnRefresh.Text = "Refresh";
            this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
            // 
            // btnMakeDir
            // 
            this.btnMakeDir.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnMakeDir.Location = new System.Drawing.Point(16, 101);
            this.btnMakeDir.Name = "btnMakeDir";
            this.btnMakeDir.Size = new System.Drawing.Size(75, 23);
            this.btnMakeDir.TabIndex = 7;
            this.btnMakeDir.Text = "Create folder";
            this.btnMakeDir.Click += new System.EventHandler(this.btnMakeDir_Click);
            // 
            // cbDrives
            // 
            this.cbDrives.ItemHeight = 13;
            this.cbDrives.Location = new System.Drawing.Point(17, 40);
            this.cbDrives.Name = "cbDrives";
            this.cbDrives.Size = new System.Drawing.Size(73, 21);
            this.cbDrives.TabIndex = 4;
            this.cbDrives.SelectedIndexChanged += new System.EventHandler(this.cbDrives_SelectedIndexChanged);
            // 
            // btnConnect
            // 
            this.btnConnect.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnConnect.Location = new System.Drawing.Point(16, 16);
            this.btnConnect.Name = "btnConnect";
            this.btnConnect.Size = new System.Drawing.Size(75, 23);
            this.btnConnect.TabIndex = 3;
            this.btnConnect.Text = "Connect...";
            this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
            // 
            // gbControl
            // 
            this.gbControl.Anchor = System.Windows.Forms.AnchorStyles.Top;
            this.gbControl.Controls.Add(this.btnStop);
            this.gbControl.Controls.Add(this.btnDelete);
            this.gbControl.Controls.Add(this.btnUpload);
            this.gbControl.Controls.Add(this.btnDownload);
            this.gbControl.Controls.Add(this.btnRefresh);
            this.gbControl.Controls.Add(this.btnMakeDir);
            this.gbControl.Controls.Add(this.cbDrives);
            this.gbControl.Controls.Add(this.btnConnect);
            this.gbControl.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.gbControl.Location = new System.Drawing.Point(4, 3);
            this.gbControl.Name = "gbControl";
            this.gbControl.Size = new System.Drawing.Size(106, 263);
            this.gbControl.TabIndex = 25;
            this.gbControl.TabStop = false;
            this.gbControl.Text = "Controls";
            // 
            // gbTransfer
            // 
            this.gbTransfer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)));
            this.gbTransfer.Controls.Add(this.rbBin);
            this.gbTransfer.Controls.Add(this.rbAsc);
            this.gbTransfer.Controls.Add(this.cbModeZ);
            this.gbTransfer.Controls.Add(this.cbST);
            this.gbTransfer.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.gbTransfer.Location = new System.Drawing.Point(4, 271);
            this.gbTransfer.Name = "gbTransfer";
            this.gbTransfer.Size = new System.Drawing.Size(106, 205);
            this.gbTransfer.TabIndex = 29;
            this.gbTransfer.TabStop = false;
            this.gbTransfer.Text = "Transfer";
            // 
            // cbModeZ
            // 
            this.cbModeZ.Location = new System.Drawing.Point(16, 56);
            this.cbModeZ.Name = "cbModeZ";
            this.cbModeZ.Size = new System.Drawing.Size(68, 24);
            this.cbModeZ.TabIndex = 29;
            this.cbModeZ.Text = "Mode Z";
            this.cbModeZ.CheckedChanged += new System.EventHandler(this.cbModeZ_CheckedChanged);
            // 
            // cbST
            // 
            this.cbST.Location = new System.Drawing.Point(16, 77);
            this.cbST.Name = "cbST";
            this.cbST.Size = new System.Drawing.Size(68, 24);
            this.cbST.TabIndex = 30;
            this.cbST.Text = "Secure";
            // 
            // pbSecure
            // 
            this.pbSecure.Image = ((System.Drawing.Image)(resources.GetObject("pbSecure.Image")));
            this.pbSecure.Location = new System.Drawing.Point(37, 10);
            this.pbSecure.Name = "pbSecure";
            this.pbSecure.Size = new System.Drawing.Size(32, 31);
            this.pbSecure.TabIndex = 29;
            this.pbSecure.TabStop = false;
            this.pbSecure.Visible = false;
            // 
            // headerLeft
            // 
            this.headerLeft.BackColor = System.Drawing.Color.White;
            this.headerLeft.Image = ((System.Drawing.Image)(resources.GetObject("headerLeft.Image")));
            this.headerLeft.Location = new System.Drawing.Point(0, 0);
            this.headerLeft.Margin = new System.Windows.Forms.Padding(0);
            this.headerLeft.Name = "headerLeft";
            this.headerLeft.Size = new System.Drawing.Size(470, 59);
            this.headerLeft.TabIndex = 26;
            this.headerLeft.TabStop = false;
            // 
            // headerRight
            // 
            this.headerRight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.headerRight.BackColor = System.Drawing.Color.White;
            this.headerRight.Cursor = System.Windows.Forms.Cursors.Hand;
            this.headerRight.Image = ((System.Drawing.Image)(resources.GetObject("headerRight.Image")));
            this.headerRight.Location = new System.Drawing.Point(634, 0);
            this.headerRight.Margin = new System.Windows.Forms.Padding(0);
            this.headerRight.Name = "headerRight";
            this.headerRight.Size = new System.Drawing.Size(150, 59);
            this.headerRight.TabIndex = 28;
            this.headerRight.TabStop = false;
            this.headerRight.Click += new System.EventHandler(this.headerRight_Click);
            // 
            // btnErrorWarning
            // 
            this.btnErrorWarning.Dock = System.Windows.Forms.DockStyle.Right;
            this.btnErrorWarning.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.btnErrorWarning.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold);
            this.btnErrorWarning.Location = new System.Drawing.Point(763, 0);
            this.btnErrorWarning.Name = "btnErrorWarning";
            this.btnErrorWarning.Size = new System.Drawing.Size(21, 110);
            this.btnErrorWarning.TabIndex = 29;
            this.btnErrorWarning.Text = "!";
            this.btnErrorWarning.Click += new System.EventHandler(this.btnErrorWarning_Click);
            // 
            // trackBar
            // 
            this.trackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.trackBar.LargeChange = 10;
            this.trackBar.Location = new System.Drawing.Point(3, 441);
            this.trackBar.Maximum = 100;
            this.trackBar.Minimum = 1;
            this.trackBar.Name = "trackBar";
            this.trackBar.Size = new System.Drawing.Size(320, 45);
            this.trackBar.SmallChange = 5;
            this.trackBar.TabIndex = 30;
            this.trackBar.TickFrequency = 5;
            this.trackBar.Value = 100;
            this.trackBar.Scroll += new System.EventHandler(this.trackBar_Scroll);
            // 
            // lblSpeed
            // 
            this.lblSpeed.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.lblSpeed.Location = new System.Drawing.Point(229, 419);
            this.lblSpeed.Name = "lblSpeed";
            this.lblSpeed.Size = new System.Drawing.Size(94, 20);
            this.lblSpeed.TabIndex = 0;
            this.lblSpeed.Text = "Speed: Unlimited";
            this.lblSpeed.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // headerMiddle
            // 
            this.headerMiddle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.headerMiddle.BackColor = System.Drawing.Color.White;
            this.headerMiddle.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("headerMiddle.BackgroundImage")));
            this.headerMiddle.Controls.Add(this.pbSecure);
            this.headerMiddle.Location = new System.Drawing.Point(470, 0);
            this.headerMiddle.Name = "headerMiddle";
            this.headerMiddle.Size = new System.Drawing.Size(167, 59);
            this.headerMiddle.TabIndex = 27;
            // 
            // mainStatusStrip
            // 
            this.mainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.pbTransfer,
            this.lblProgress});
            this.mainStatusStrip.Location = new System.Drawing.Point(0, 659);
            this.mainStatusStrip.Name = "mainStatusStrip";
            this.mainStatusStrip.Size = new System.Drawing.Size(784, 22);
            this.mainStatusStrip.TabIndex = 31;
            this.mainStatusStrip.Text = "statusStrip";
            // 
            // pbTransfer
            // 
            this.pbTransfer.Name = "pbTransfer";
            this.pbTransfer.Size = new System.Drawing.Size(160, 16);
            // 
            // lblProgress
            // 
            this.lblProgress.Name = "lblProgress";
            this.lblProgress.Size = new System.Drawing.Size(60, 17);
            this.lblProgress.Text = "Welcome!";
            // 
            // mainSplitContainer
            // 
            this.mainSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.mainSplitContainer.Location = new System.Drawing.Point(0, 59);
            this.mainSplitContainer.Name = "mainSplitContainer";
            this.mainSplitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal;
            // 
            // mainSplitContainer.Panel1
            // 
            this.mainSplitContainer.Panel1.Controls.Add(this.tableLayout);
            this.mainSplitContainer.Panel1MinSize = 320;
            // 
            // mainSplitContainer.Panel2
            // 
            this.mainSplitContainer.Panel2.Controls.Add(this.tbLog);
            this.mainSplitContainer.Panel2.Controls.Add(this.btnErrorWarning);
            this.mainSplitContainer.Panel2MinSize = 30;
            this.mainSplitContainer.Size = new System.Drawing.Size(784, 596);
            this.mainSplitContainer.SplitterDistance = 482;
            this.mainSplitContainer.TabIndex = 32;
            // 
            // tableLayout
            // 
            this.tableLayout.ColumnCount = 3;
            this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120F));
            this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            this.tableLayout.Controls.Add(this.panelMiddle, 1, 0);
            this.tableLayout.Controls.Add(this.panelLeft, 0, 0);
            this.tableLayout.Controls.Add(this.panelRight, 2, 0);
            this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tableLayout.Location = new System.Drawing.Point(0, 0);
            this.tableLayout.Name = "tableLayout";
            this.tableLayout.RowCount = 1;
            this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayout.Size = new System.Drawing.Size(784, 482);
            this.tableLayout.TabIndex = 31;
            // 
            // panelMiddle
            // 
            this.panelMiddle.Controls.Add(this.gbControl);
            this.panelMiddle.Controls.Add(this.gbTransfer);
            this.panelMiddle.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panelMiddle.Location = new System.Drawing.Point(335, 3);
            this.panelMiddle.Name = "panelMiddle";
            this.panelMiddle.Size = new System.Drawing.Size(114, 476);
            this.panelMiddle.TabIndex = 34;
            // 
            // panelLeft
            // 
            this.panelLeft.Controls.Add(this.lblServerDirectory);
            this.panelLeft.Controls.Add(this.trackBar);
            this.panelLeft.Controls.Add(this.listServer);
            this.panelLeft.Controls.Add(this.lblServer);
            this.panelLeft.Controls.Add(this.lblSpeed);
            this.panelLeft.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panelLeft.Location = new System.Drawing.Point(3, 3);
            this.panelLeft.Name = "panelLeft";
            this.panelLeft.Size = new System.Drawing.Size(326, 476);
            this.panelLeft.TabIndex = 33;
            // 
            // panelRight
            // 
            this.panelRight.Controls.Add(this.lblLocalDirectory);
            this.panelRight.Controls.Add(this.lblLocal);
            this.panelRight.Controls.Add(this.listLocal);
            this.panelRight.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panelRight.Location = new System.Drawing.Point(455, 3);
            this.panelRight.Name = "panelRight";
            this.panelRight.Size = new System.Drawing.Size(326, 476);
            this.panelRight.TabIndex = 32;
            // 
            // MainForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(784, 681);
            this.Controls.Add(this.mainSplitContainer);
            this.Controls.Add(this.headerRight);
            this.Controls.Add(this.headerMiddle);
            this.Controls.Add(this.headerLeft);
            this.Controls.Add(this.mainStatusStrip);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.KeyPreview = true;
            this.MinimumSize = new System.Drawing.Size(640, 720);
            this.Name = "MainForm";
            this.Text = "Simple WinForm FTP Client";
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_Closing);
            this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.MainForm_KeyPress);
            this.gbControl.ResumeLayout(false);
            this.gbTransfer.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.pbSecure)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.headerLeft)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.headerRight)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.trackBar)).EndInit();
            this.headerMiddle.ResumeLayout(false);
            this.mainStatusStrip.ResumeLayout(false);
            this.mainStatusStrip.PerformLayout();
            this.mainSplitContainer.Panel1.ResumeLayout(false);
            this.mainSplitContainer.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.mainSplitContainer)).EndInit();
            this.mainSplitContainer.ResumeLayout(false);
            this.tableLayout.ResumeLayout(false);
            this.panelMiddle.ResumeLayout(false);
            this.panelLeft.ResumeLayout(false);
            this.panelLeft.PerformLayout();
            this.panelRight.ResumeLayout(false);
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        /// <summary>
        /// win form client starts here
        /// </summary>
        [STAThread]
        static void Main()
        {
            // set the trial license key
            Rebex.Licensing.Key = Rebex.Samples.TrialKey.Key;


            Application.Run(new MainForm());
        }

        /// <summary>
        /// connect/disconnect ftp server
        /// </summary>
        private async void btnConnect_Click(object sender, System.EventArgs e)
        {
            if (_ftp != null)
            {
                if (_isWorking)
                    return;

                // disconnect

                trackBar.Enabled = false;
                _ftp.Disconnect();
                _ftp.Dispose();
                _ftp = null;
                btnConnect.Text = "Connect...";
                MakeFtpList(); // clearing
                return;
            }

            // connection dialog

            ConnectionFormData connectionData = new ConnectionFormData(FileTransferComponent.Ftp);
            connectionData.LoadConfig();

            ConnectionForm con = new ConnectionForm(connectionData);

            // show connection dialog

            con.ShowDialog();

            // not confirmed

            if (con.DialogResult != DialogResult.OK)
                return;

            // save confirmed connection settings
            con.Data.SaveConfig();

            // create ftp object
            _ftp = new Ftp();

            // assign the logger
            _ftp.LogWriter = new RichTextBoxLogWriter(tbLog, tbLog.MaxLength, con.Data.LogLevel);

            // set event handlers
            _ftp.StateChanged += StateChanged;
            _ftp.Traversing += Traversing;
            _ftp.TransferProgressChanged += TransferProgressChanged;
            _ftp.DeleteProgressChanged += DeleteProgressChanged;
            _ftp.ProblemDetected += ProblemDetected;

            try
            {
                _ftp.Passive = con.Data.PassiveMode;
                _ftp.Settings.UseLargeBuffers = true;
                _ftp.Timeout = 30000;

                // proxy

                if (con.Data.ProxyType != FileTransferProxyType.None)
                {
                    _ftp.Proxy = new FtpProxy((FtpProxyType)con.Data.ProxyType, con.Data.ProxyHost, con.Data.ProxyPort);
                    if (con.Data.ProxyUser.Length > 0)
                        _ftp.Proxy.Credentials = new System.Net.NetworkCredential(con.Data.ProxyUser, con.Data.ProxyPassword);
                }

                SslMode securityMode = ConvertToSslMode(con.Data.FileTransferMode);
                if (securityMode != SslMode.None)
                {
                    _ftp.ValidatingCertificate += Verifier.ValidatingCertificate;

                    if (con.Data.ClientCertificateFilename != null && con.Data.ClientCertificateFilename.Trim() != string.Empty)
                    {
                        PassphraseDialog pp = new PassphraseDialog();
                        if (pp.ShowDialog() == DialogResult.OK)
                        {
                            CertificateChain chain = CertificateChain.LoadPfx(con.Data.ClientCertificateFilename, pp.Passphrase);
                            _ftp.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.CreateRequestHandler(chain);
                        }
                        else
                        {
                            throw new ApplicationException("Passphrase wasn't entered.");
                        }
                    }
                    else
                    {
                        _ftp.Settings.SslClientCertificateRequestHandler = new RequestHandler();
                    }

                    _ftp.SecureTransfers = cbST.Checked;
                }
                
                _ftp.Settings.SslAllowedSuites = con.Data.AllowedSuite;
                _ftp.Settings.SslAllowedVersions = con.Data.TlsProtocol;

                // connect

                btnStop.Visible = true;
                _isWorking = true;

                try
                {
                    await _ftp.ConnectAsync(con.Data.ServerHost, con.Data.ServerPort, securityMode);
                }
                finally
                {
                    btnStop.Visible = false;
                    _isWorking = false;
                }
                if (securityMode == SslMode.None)
                {
                    cbST.Checked = false;
                    cbST.Enabled = false;
                    pbSecure.Visible = false;
                }
                else
                {
                    cbST.Checked = true;
                    cbST.Enabled = true;
                    pbSecure.Visible = true;
                }
                // login
                if (!_ftp.IsAuthenticated)
                    await _ftp.LoginAsync(con.Data.ServerUser, con.Data.ServerPassword);

                if (cbModeZ.Checked)
                    _ftp.TransferMode = FtpTransferMode.Zlib;

                // ccc
                if (con.Data.ClearCommandChannel && securityMode != SslMode.None)
                {
                    try
                    {
                        _ftp.SecureTransfers = true;
                        _ftp.ClearCommandChannel();
                        cbST.Checked = true;
                        cbST.Enabled = false;
                        _cccMode = true;
                    }
                    catch (Exception ex)
                    {
                        WriteToLog(ex);
                    }
                }
                trackBar.Enabled = true;
                btnErrorWarning.Visible = false;
                btnConnect.Text = "Disconnect";
                MakeFtpList();
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
                if (_ftp != null)
                {
                    _ftp.Dispose();
                    _ftp = null;
                }
            }
            finally
            {
                _isWorking = false;
            }
        }

        /// <summary>
        /// disconnect on exit
        /// </summary>
        private void MainForm_Closing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            if (_ftp != null)
                _ftp.Dispose();
        }

        /// <summary>
        /// CWD or GET file command on server side
        /// </summary>
        private void ListServerClick()
        {
            try
            {
                if (listServer.Items.Count < 1)
                    return;

                if (listServer.SelectedItems.Count < 1)
                    listServer.Items[0].Selected = true;

                listServer.Focus();

                // ftp state test

                if (_isWorking)
                    return;

                int index = listServer.SelectedIndices[0];
                ListViewItem item = listServer.SelectedItems[0];

                if (index >= _serverDirs)
                {
                    // GET file

                    DownloadFiles(item.Text, _localPath);
                }
                else
                {
                    // CWD

                    string directory;
                    if (index == 0)
                        directory = "..";
                    else
                        directory = item.Text;

                    _ftp.ChangeDirectory(directory);

                    MakeFtpList();
                }
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        private void listServer_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                ListServerClick();
                listServer.Focus();
            }
        }

        private void listServer_DoubleClick(object sender, System.EventArgs e)
        {
            ListServerClick();
            listServer.Focus();
        }

        /// <summary>
        /// change drive letter
        /// </summary>
        private void cbDrives_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            try
            {
                _localPath = cbDrives.SelectedItem.ToString();
                MakeLocalList();
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
                listLocal.Items.Clear();
                lblLocalDirectory.Text = lblLocal.Text = null;
            }
        }

        /// <summary>
        /// LCD or PUT command on local side
        /// </summary>
        private void ListLocalClick()
        {
            try
            {
                if (listLocal.Items.Count < 1)
                    return;

                if (listLocal.SelectedItems.Count < 1)
                    listLocal.Items[0].Selected = true;

                listLocal.Focus();

                int index = listLocal.SelectedIndices[0];
                ListViewItem item = listLocal.SelectedItems[0];

                if (index >= _localDirs)
                {
                    // upload file

                    UploadFiles(item.Text, _localPath);
                }
                else
                {
                    // local change directory

                    _localPath = Path.Combine(_localPath, item.Text);
                    MakeLocalList();
                }
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        private void listLocal_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                ListLocalClick();
                if (listLocal.Items.Count > 0)
                {
                    listLocal.Focus();
                }
            }
        }

        private void listLocal_DoubleClick(object sender, System.EventArgs e)
        {
            ListLocalClick();
            listLocal.Focus();
        }

        /// <summary>
        /// make dir
        /// </summary>
        private void btnMakeDir_Click(object sender, System.EventArgs e)
        {
            try
            {
                MakeDir dir = new MakeDir();

                // FTP: MKDIR

                if (listActive == listServer)
                {
                    if (_isWorking)
                        return;

                    dir.ShowDialog();
                    if (dir.Directory != null)
                    {
                        _ftp.CreateDirectory(dir.Directory);
                        MakeFtpList();
                    }
                }
                else
                {
                    // LOCAL: MKDIR

                    dir.ShowDialog();

                    if (dir.Directory != null)
                    {
                        Directory.CreateDirectory(Path.Combine(_localPath, dir.Directory));
                        MakeLocalList();
                    }
                }
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        /// <summary>
        /// refresh listing
        /// </summary>
        private void btnRefresh_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (listActive == listServer)
                {
                    if (_isWorking)
                        return;

                    MakeFtpList();
                }
                else
                {
                    MakeLocalList();
                }
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        private void PrepareTransfer()
        {
            // secure transfers

            if (cbST.Enabled && !_cccMode)
                _ftp.SecureTransfers = cbST.Checked;

            // set asc/bin transfers

            if (rbBin.Checked)
                _ftp.TransferType = FtpTransferType.Binary;
            else
                _ftp.TransferType = FtpTransferType.Ascii;

            // transfer


            _isWorking = true;
            btnStop.Visible = true;
            _problemForm.Initialize();
            _transferTime = DateTime.Now;
        }

        /// <summary>
        /// download file or directory tree
        /// </summary>
        /// <param name="fileName">remote file name</param>
        /// <param name="localPath">local path</param>
        private async void DownloadFiles(string fileName, string localPath)
        {
            // ftp state test
            if (_isWorking)
                return;

            PrepareTransfer();

            try
            {
                await _ftp.DownloadAsync(fileName, localPath, TraversalMode.Recursive, TransferMethod.Copy, ActionOnExistingFiles.ThrowException);
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
            finally
            {
                MakeLocalList();
                TransferCompleted();
            }
        }

        /// <summary>
        /// upload file or directory tree
        /// </summary>
        /// <param name="fileName">local file name</param>
        /// <param name="localPath">local path</param>
        private async void UploadFiles(string fileName, string localPath)
        {
            // ftp state test
            if (_ftp == null)
            {
                WriteToLog("Not connected!", Color.DarkOrange);
                return;
            }
            if (_isWorking)
                return;

            localPath = Path.Combine(localPath, fileName);

            PrepareTransfer();

            try
            {
                await _ftp.UploadAsync(localPath, ".", TraversalMode.Recursive, TransferMethod.Copy, ActionOnExistingFiles.ThrowException);
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
            finally
            {
                MakeFtpList();
                TransferCompleted();
            }


        }

        private void TransferCompleted()
        {
            btnStop.Visible = false;
            _isWorking = false;
            SetProgressValue(0);
        }

        /// <summary>
        /// show transfer status: files, bytes, time, speed
        /// </summary>
        private void ShowTransferStatus(long bytesTransferred, int filesTransferred)
        {
            // unknown bytes transferred
            if (bytesTransferred == 0)
                return;

            // files and bytes transferred
            string outstring = string.Format("{0} file{1} ({2} byte{3}) transferred in",
                filesTransferred, (filesTransferred > 1 ? "s" : null),
                bytesTransferred, (bytesTransferred > 1 ? "s" : null));

            // time spent
            TimeSpan ts = DateTime.Now - _transferTime;

            // speed
            if (ts.TotalSeconds > 1)
            {
                outstring += (ts.Days > 0 ? " " + ts.Days + " day" + (ts.Days > 1 ? "s" : null) : null);
                outstring += (ts.Hours > 0 ? " " + ts.Hours + " hour" + (ts.Hours > 1 ? "s" : null) : null);
                outstring += (ts.Minutes > 0 ? " " + ts.Minutes + " min" + (ts.Minutes > 1 ? "s" : null) : null);
                outstring += (ts.Seconds > 0 ? " " + ts.Seconds + " sec" + (ts.Seconds > 1 ? "s" : null) : null);
            }
            else
            {
                outstring += " " + ts.TotalSeconds + " sec";
            }

            double speed = bytesTransferred / ts.TotalSeconds;
            if (speed < 1)
                outstring += string.Format(" at {0:F3} B/s", speed);
            else if (speed < 1024)
                outstring += string.Format(" at {0:F0} B/s", speed);
            else
                outstring += string.Format(" at {0:F0} KB/s", speed / 1024);


            WriteToLog("> " + outstring, RichTextBoxLogWriter.COLORCOMMAND);
        }

        /// <summary>
        /// handle download button click
        /// </summary>
        private void btnDownload_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (listActive != listServer)
                    return;

                if (_isWorking)
                    return;

                if (listServer.SelectedItems.Count > 0)
                    DownloadFiles(listServer.SelectedItems[0].Text, _localPath);
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        /// <summary>
        /// handle upload button click
        /// </summary>
        private void btnUpload_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (listActive == listServer)
                    return;

                if (_isWorking)
                    return;

                if (listLocal.SelectedItems.Count > 0)
                    UploadFiles(listLocal.SelectedItems[0].Text, _localPath);
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        /// <summary>
        /// handle delete button click
        /// </summary>
        private void btnDelete_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (listActive == listServer)
                {
                    if (_isWorking)
                        return;

                    if (listServer.SelectedItems.Count > 0)
                    {
                        int index = listServer.SelectedIndices[0];
                        ListViewItem item = listServer.SelectedItems[0];

                        if (index >= _serverDirs)
                        {
                            DeleteDialog dialog = new DeleteDialog(DeleteDialog.DialogPrompt.DeleteFile);
                            dialog.Path = item.Text;
                            dialog.ShowDialog();

                            if (dialog.OK)
                            {
                                _ftp.DeleteFile(item.Text);
                                MakeFtpList();
                            }
                        }
                        else
                        {
                            DeleteDialog dialog = new DeleteDialog(DeleteDialog.DialogPrompt.DeleteDirectory);
                            dialog.Path = item.Text;
                            dialog.ShowDialog();

                            if (dialog.OK)
                            {
                                _ftp.Delete(item.Text, TraversalMode.Recursive);
                                MakeFtpList();
                            }
                        }
                    }
                }
                else
                {
                    if (listLocal.SelectedItems.Count > 0)
                    {
                        int index = listLocal.SelectedIndices[0];
                        ListViewItem item = listLocal.SelectedItems[0];
                        string path = Path.Combine(_localPath, item.Text);

                        if (index >= _localDirs)
                        {
                            DeleteDialog dialog = new DeleteDialog(DeleteDialog.DialogPrompt.DeleteFile);
                            dialog.Path = item.Text;
                            dialog.ShowDialog();

                            if (dialog.OK)
                            {
                                File.Delete(path);
                                MakeLocalList();
                            }
                        }
                        else
                        {
                            DeleteDialog dialog = new DeleteDialog(DeleteDialog.DialogPrompt.DeleteDirectory);
                            dialog.Path = item.Text;
                            dialog.ShowDialog();

                            if (dialog.OK)
                            {
                                Directory.Delete(path, false);
                                MakeLocalList();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WriteToLog(ex);
            }
        }

        /// <summary>
        /// activate panel on focus event
        /// </summary>
        private void listServer_Enter(object sender, System.EventArgs e)
        {
            listActive = listServer;
            lblServerDirectory.BackColor = SystemColors.ActiveCaption;
            lblServerDirectory.ForeColor = SystemColors.ActiveCaptionText;
            lblLocalDirectory.BackColor = SystemColors.InactiveCaption;
            lblLocalDirectory.ForeColor = SystemColors.InactiveCaptionText;
        }

        /// <summary>
        /// activate panel on focus event
        /// </summary>
        private void listLocal_Enter(object sender, System.EventArgs e)
        {
            listActive = listLocal;
            lblServerDirectory.BackColor = SystemColors.InactiveCaption;
            lblServerDirectory.ForeColor = SystemColors.InactiveCaptionText;
            lblLocalDirectory.BackColor = SystemColors.ActiveCaption;
            lblLocalDirectory.ForeColor = SystemColors.ActiveCaptionText;
        }

        /// <summary>
        /// stop transfer when something is being transferred
        /// </summary>
        private void btnStop_Click(object sender, System.EventArgs e)
        {
            _ftp.Abort();
        }

        /// <summary>
        /// go to the url
        /// </summary>
        private void headerRight_Click(object sender, System.EventArgs e)
        {
            var info = new ProcessStartInfo(URL);
            info.UseShellExecute = true;
            info.Verb = "open";
            Process.Start(info);
        }

        /// <summary>
        /// space bar for changing panels server <-> local
        /// </summary>
        private void MainForm_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == Convert.ToChar(Keys.Space))
            {
                if (listActive == listLocal)
                    listServer.Focus();
                else
                    listLocal.Focus();
            }
        }

        private void btnErrorWarning_Click(object sender, System.EventArgs e)
        {
            MessageBox.Show(_exception, "Last occured error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void trackBar_Scroll(object sender, EventArgs e)
        {
            if (trackBar.Value == 100)
            {
                lblSpeed.Text = "Speed: Unlimited";
                _ftp.MaxDownloadSpeed = 0;
                _ftp.MaxUploadSpeed = 0;
            }
            else
            {
                lblSpeed.Text = string.Format("Speed: {0} kB/s", trackBar.Value);
                _ftp.MaxDownloadSpeed = trackBar.Value;
                _ftp.MaxUploadSpeed = trackBar.Value;
            }
        }

        private void cbModeZ_CheckedChanged(object sender, EventArgs e)
        {
            Ftp client = _ftp;
            if (client == null)
                return;

            if (cbModeZ.Checked)
                client.TransferMode = FtpTransferMode.Zlib;
            else
                client.TransferMode = FtpTransferMode.Stream;
        }

    }

    #region ListViewColumnSorter

    public class ListViewColumnSorter : MultiComparer, IComparer
    {
        public ListViewColumnSorter()
            : base(new FileSystemItemComparer(FileSystemItemComparerType.FileType, SortingOrder.Ascending), new FileSystemItemComparer(FileSystemItemComparerType.Name))
        {
        }

        int IComparer.Compare(object x, object y)
        {
            ListViewItem listViewX = (ListViewItem)x;
            ListViewItem listViewY = (ListViewItem)y;

            FtpItem itemX = (FtpItem)listViewX.Tag;
            FtpItem itemY = (FtpItem)listViewY.Tag;

            if (itemX == null)
            {
                if (itemY == null)
                    return 0;

                return -1;
            }
            else if (itemY == null)
            {
                return 1;
            }

            return base.Compare(itemX, itemY);
        }
    }

    #endregion
}
