'  
'   Rebex Sample Code License
' 
'   Copyright 2025, 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.
' 

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

Imports Rebex.IO
Imports Rebex.Net
Imports Rebex.Security.Certificates
Imports System.Net

''' <summary>
''' very simple FTP and/or SFTP client
''' </summary>
Public Class MainForm
    Inherits System.Windows.Forms.Form

    Private components As System.ComponentModel.Container = Nothing
    Private tbLog As System.Windows.Forms.RichTextBox
    Private WithEvents listServer As System.Windows.Forms.ListView
    Private itemName As System.Windows.Forms.ColumnHeader
    Private itemSize As System.Windows.Forms.ColumnHeader
    Private lblServer As System.Windows.Forms.Label
    Private WithEvents listLocal As System.Windows.Forms.ListView
    Private lblLocal As System.Windows.Forms.Label
    Private WithEvents lblServerDirectory As System.Windows.Forms.Label
    Private columnHeader1 As System.Windows.Forms.ColumnHeader
    Private columnHeader2 As System.Windows.Forms.ColumnHeader
    Private WithEvents lblLocalDirectory As System.Windows.Forms.Label
    Private itemDate As System.Windows.Forms.ColumnHeader
    Private columnHeader3 As System.Windows.Forms.ColumnHeader
    Private WithEvents btnStop As System.Windows.Forms.Button
    Private WithEvents btnDelete As System.Windows.Forms.Button
    Private WithEvents btnUpload As System.Windows.Forms.Button
    Private WithEvents btnDownload As System.Windows.Forms.Button
    Private rbBin As System.Windows.Forms.RadioButton
    Private rbAsc As System.Windows.Forms.RadioButton
    Private WithEvents btnRefresh As System.Windows.Forms.Button
    Private WithEvents btnMakeDir As System.Windows.Forms.Button
    Private WithEvents cbDrives As System.Windows.Forms.ComboBox
    Private WithEvents btnConnect As System.Windows.Forms.Button
    Private gbControl As System.Windows.Forms.GroupBox
    Private gbTransfer As System.Windows.Forms.GroupBox
    Private headerLeft As System.Windows.Forms.PictureBox
    Private headerMiddle As System.Windows.Forms.Panel
    Private WithEvents headerRight As System.Windows.Forms.PictureBox
    Private WithEvents trackBar As System.Windows.Forms.TrackBar
    Private lblSpeed As System.Windows.Forms.Label
    Private WithEvents btnErrorWarning As System.Windows.Forms.Button
    Private pbSecure As System.Windows.Forms.PictureBox

    Private _client As FileTransferClient
    ' FTP or SFTP session
    Private ReadOnly _connectionData As ConnectionFormData
    ' connection fields gathered from the connection form
    Private listActive As ListView
    ' active list (server x local)
    Private _serverDirs As Integer
    ' number of dirs on server side
    Private _localDirs As Integer
    ' number of dirs on local side
    Private _selectedDrive As Integer = -1
    ' selected drive (A:, C:, ...) in combo
    Private _localPath As String
    ' local path
    Private _isWorking As Boolean
    ' last TransferProgress event call time
    Private _transferTime As DateTime
    ' transfer launch-time
    Private _problemForm As ProblemDetectedForm
    ' informs the user about problems while transferring data
    ' constants
    Private Const SYMLINK As String = "--->"
    ' symlink tag
    Private Const URL As String = "https://www.rebex.net/file-transfer-pack/"
    Private mainStatusStrip As StatusStrip
    Private pbTransfer As ToolStripProgressBar
    Private lblProgress As ToolStripStatusLabel
    Private mainSplitContainer As SplitContainer
    Private WithEvents tableLayout As TableLayoutPanel
    Private WithEvents Panel1 As Panel
    Private WithEvents panelLeft As Panel
    Private WithEvents panelMiddle As Panel
    ' url
    Private _exception As String = ""
    ' last occurred exception
    Public Sub WriteToLog(x As Exception)
        If TypeOf x Is AggregateException Then
            For Each inner As Exception In DirectCast(x, AggregateException).InnerExceptions
                WriteToLog(inner)
            Next
            Return
        End If

        ShowErrorWarning(x.ToString())

        ' FtpExceptions and SftpExceptions are automatically logged by component logger.
        ' No need to display them again.
        ' We don't wont duplicate entries for such exceptions.
        If TypeOf x Is FtpException OrElse TypeOf x Is SftpException Then
            Return
        End If

        WriteToLog("* " & x.ToString(), RichTextBoxLogWriter.COLORERROR)
    End Sub

    Public Sub ShowErrorWarning(message As String)
        _exception = message
        btnErrorWarning.Visible = True
    End Sub

    Public Sub WriteToLog(message As String, color As Color)
        tbLog.Focus()
        tbLog.SelectionColor = color
        tbLog.AppendText(message & vbCr & vbLf)
    End Sub


    ''' <summary>
    ''' format datetime to readable form in the panels
    ''' </summary>
    ''' <param name="dt">datetime</param>
    ''' <returns>formatted string</returns>
    Private Shared Function FormatFileTime(dt As DateTime) As String
        Return dt.ToString("yyyy-MM-dd HH:mm")
    End Function

    ''' <summary>
    ''' handles the displaying traversing event
    ''' </summary>
    Private Sub Traversing(sender As Object, e As TraversingEventArgs)
        If e.Action = TransferAction.Listing Then
            Return
        End If

        Dim strBatchInfo As String = String.Format("({0} file{1} traversed)    ", e.FilesTotal, (If(e.FilesTotal > 1, "s", Nothing)))

        Select Case e.TraversingState
            Case TraversingState.DirectoryRetrieved
                strBatchInfo += "Directory retrieved."
                Exit Select
            Case TraversingState.DirectoryRetrieving
                strBatchInfo += "Retrieving directory..."
                Exit Select
            Case TraversingState.HierarchyRetrieved
                strBatchInfo += String.Format("Hierarchy retrieved ({0} byte{1} in {2} file{3}).", e.BytesTotal, (If(e.BytesTotal > 1, "s", Nothing)), e.FilesTotal, (If(e.FilesTotal > 1, "s", Nothing)))
                Exit Select
            Case TraversingState.HierarchyRetrieving
                strBatchInfo += "Retrieving hierarchy..."
                Exit Select
        End Select

        lblProgress.Text = strBatchInfo
    End Sub

    ''' <summary>
    ''' handles the transfer progress changed event
    ''' </summary>
    Private Sub TransferProgressChanged(sender As Object, e As TransferProgressChangedEventArgs)
        Dim strBatchInfo As String = String.Format("({0} / {1} file{2} processed)    ", e.FilesProcessed, e.FilesTotal, (If(e.FilesProcessed > 1, "s", Nothing)))

        SetProgressValue(Convert.ToInt32(e.ProgressPercentage))

        Select Case e.TransferState
            Case TransferProgressState.DataBlockProcessed
                strBatchInfo += e.BytesTransferred & " bytes"
                Exit Select
            Case TransferProgressState.DirectoryProcessing
                strBatchInfo += "Processing directory..."
                Exit Select
            Case TransferProgressState.FileTransferring
                strBatchInfo += "Transferring file..."
                Exit Select
            Case TransferProgressState.FileTransferred
                strBatchInfo += "File transferred."
                Exit Select
            Case TransferProgressState.TransferCompleted
                strBatchInfo += "Transfer completed."
                ShowTransferStatus(e.BytesTransferred, e.FilesTransferred)
                Exit Select
        End Select

        lblProgress.Text = strBatchInfo
    End Sub

    Private Sub SetProgressValue(value As Integer)
        ' workaround for progress bar smoothing
        If value = 100 Then
            pbTransfer.Maximum = 101
            pbTransfer.Value = 101
            pbTransfer.Maximum = 100
            System.Threading.Thread.Sleep(200)
        Else
            pbTransfer.Value = value
        End If
    End Sub

    ''' <summary>
    ''' handles the delete progress changed event
    ''' </summary>
    Private Sub DeleteProgressChanged(sender As Object, e As DeleteProgressChangedEventArgs)
        Dim strDeleteInfo As String = String.Format("({0} / {1} file{2} deleted)    ", e.FilesProcessed, e.FilesTotal, (If(e.FilesProcessed > 1, "s", Nothing)))

        Select Case e.DeleteState
            Case DeleteProgressState.DeleteCompleted
                strDeleteInfo += "Delete completed."
                Exit Select
            Case DeleteProgressState.DirectoryDeleted
                strDeleteInfo += "Directory deleted."
                Exit Select
            Case DeleteProgressState.DirectoryProcessing
                strDeleteInfo += "Processing directory..."
                Exit Select
            Case DeleteProgressState.FileDeleted
                strDeleteInfo += "File deleted."
                Exit Select
            Case DeleteProgressState.FileDeleting
                strDeleteInfo += "Deleting file..."
                Exit Select
        End Select

        lblProgress.Text = strDeleteInfo
    End Sub

    ''' <summary>
    ''' handles the batch transfer problem detected event
    ''' </summary>
    Private Sub ProblemDetected(sender As Object, e As ProblemDetectedEventArgs)
        _problemForm.ShowModal(Me, e)
    End Sub

    ''' <summary>
    ''' make local list + drives combo box
    ''' </summary>
    Public Sub MakeLocalList()
        Dim dirs As Integer = 0
        Dim files As Integer = 0
        Dim size As Long = 0

        ' make a logical drives list [first run only]

        If cbDrives.Items.Count <= 0 Then
            Dim drives As String() = Directory.GetLogicalDrives()
            Dim lowerDrive As String = "c:\"

            ' find "lower" acceptable drive

            For c As Integer = drives.Length - 1 To 0 Step -1
                If drives(c).ToLower().CompareTo("c:\") >= 0 Then
                    lowerDrive = drives(c).ToLower()
                End If
            Next

            ' feed the drives' list and select one

            For c As Integer = 0 To drives.Length - 1
                Dim drive As String = drives(c)

                cbDrives.Items.Add(drive)

                If _selectedDrive = -1 AndAlso drive.ToLower().CompareTo(lowerDrive) = 0 Then
                    cbDrives.SelectedIndex = c
                    _selectedDrive = c
                End If
            Next

            If cbDrives.SelectedIndex <= 0 Then
                cbDrives.SelectedIndex = 0
            End If
        End If

        ' create the list
        listLocal.Items.Clear()

        ' directory up
        If _localPath IsNot Nothing AndAlso _localPath.Length > 3 Then
            listLocal.Items.Add(New ListViewItem("..", 0))
            dirs += 1
        Else
            _localPath = cbDrives.SelectedItem.ToString()
        End If

        Dim localDirectory As New DirectoryInfo(_localPath)
        Dim list As DirectoryInfo() = localDirectory.GetDirectories()

        For c As Integer = 0 To list.Length - 1
            Dim row As String() = New String(2) {}
            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) = ""
            End Try

            listLocal.Items.Add(New ListViewItem(row, 1 + c))
            dirs += 1
        Next

        _localDirs = dirs

        ' files

        Dim list2 As FileInfo() = localDirectory.GetFiles()

        For c As Integer = 0 To list2.Length - 1
            Dim row As String() = New String(2) {}
            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 += 1
        Next

        ' stats

        lblLocal.Text = dirs & " folder" & (If(dirs > 1, "s", "")) & ", " & files & " file" & (If(files > 1, "s", "")) & ", " & size \ 1024 & " K"

        ' working directory

        lblLocalDirectory.Text = localDirectory.FullName
        _localPath = localDirectory.FullName
    End Sub

    ''' <summary>
    ''' make remote list
    ''' </summary>
    Public Async Sub MakeRemoteList()
        Dim dirs As Integer = 0
        Dim files As Integer = 0
        Dim size As Long = 0

        listServer.Items.Clear()

        ' not connected?

        If _client Is Nothing Then
            lblServerDirectory.Text = ""
            lblServer.Text = ""
            _serverDirs = 0
            Return
        End If

        '''/ secure transfers
        'if (cbST.Enabled && !_cccMode)
        '    _client.SecureTransfers = cbST.Checked;

        ' make the list
        Dim list As FileSystemItemCollection = Nothing
        Try
            _isWorking = True
            btnStop.Visible = True

            list = Await _client.GetListAsync()

            list.Sort()
        Catch ex As Exception
            WriteToLog(ex)
            listServer.Items.Add(New ListViewItem("..", 0))
            Return
        Finally
            btnStop.Visible = False
            _isWorking = False
        End Try

        ' directories

        listServer.Items.Add(New ListViewItem("..", 0))
        dirs += 1

        For c As Integer = 0 To list.Count - 1
            Dim row As String() = New String(2) {}
            row(0) = list(c).Name
            row(1) = Nothing
            row(2) = If(list(c).LastWriteTime.HasValue, FormatFileTime(list(c).LastWriteTime.Value), Nothing)

            If list(c).IsLink Then
                row(1) = SYMLINK
            ElseIf list(c).IsFile Then
                row(1) = list(c).Length.ToString()
                size += list(c).Length
                files += 1
            ElseIf list(c).IsDirectory Then
                dirs += 1
            End If

            Dim lvi As New ListViewItem(row)
            lvi.Tag = list(c)

            listServer.Items.Add(lvi)
        Next

        listServer.ListViewItemSorter = New ListViewColumnSorter()
        listServer.Sort()

        ' stats
        lblServer.Text = dirs & " folder" & (If(dirs > 1, "s", "")) & ", " & files & " file" & (If(files > 1, "s", "")) & ", " & size \ 1024 & " K"

        ' working directory
        lblServerDirectory.Text = _client.GetCurrentDirectory()

        _serverDirs = dirs
    End Sub

    ''' <summary>
    ''' constructor
    ''' </summary>
    Public Sub New()
        Application.EnableVisualStyles()
        CheckForIllegalCrossThreadCalls = True
        InitializeComponent()

        rbBin.Checked = True
        trackBar.Enabled = False
        btnErrorWarning.Visible = False
        lblServer.Text = ""
        listLocal.Focus()
        btnConnect.[Select]()

        _connectionData = New ConnectionFormData(FileTransferComponent.FileTransfer)
        _connectionData.LoadConfig()

        MakeLocalList()
        _problemForm = New ProblemDetectedForm()

        WriteToLog("Welcome to Rebex File Transfer sample app!", Color.DarkGreen)
    End Sub

    ''' <summary>
    ''' clean up any resources being used
    ''' </summary>
    Protected Overrides Sub Dispose(disposing As Boolean)
        If disposing Then
            If components IsNot Nothing Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

#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 Sub InitializeComponent()
        Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MainForm))
        Me.listServer = New System.Windows.Forms.ListView()
        Me.itemName = New System.Windows.Forms.ColumnHeader()
        Me.itemSize = New System.Windows.Forms.ColumnHeader()
        Me.itemDate = New System.Windows.Forms.ColumnHeader()
        Me.listLocal = New System.Windows.Forms.ListView()
        Me.columnHeader1 = New System.Windows.Forms.ColumnHeader()
        Me.columnHeader2 = New System.Windows.Forms.ColumnHeader()
        Me.columnHeader3 = New System.Windows.Forms.ColumnHeader()
        Me.tbLog = New System.Windows.Forms.RichTextBox()
        Me.lblServer = New System.Windows.Forms.Label()
        Me.lblServerDirectory = New System.Windows.Forms.Label()
        Me.lblLocal = New System.Windows.Forms.Label()
        Me.lblLocalDirectory = New System.Windows.Forms.Label()
        Me.btnStop = New System.Windows.Forms.Button()
        Me.btnDelete = New System.Windows.Forms.Button()
        Me.btnUpload = New System.Windows.Forms.Button()
        Me.btnDownload = New System.Windows.Forms.Button()
        Me.rbBin = New System.Windows.Forms.RadioButton()
        Me.rbAsc = New System.Windows.Forms.RadioButton()
        Me.btnRefresh = New System.Windows.Forms.Button()
        Me.btnMakeDir = New System.Windows.Forms.Button()
        Me.cbDrives = New System.Windows.Forms.ComboBox()
        Me.btnConnect = New System.Windows.Forms.Button()
        Me.gbControl = New System.Windows.Forms.GroupBox()
        Me.gbTransfer = New System.Windows.Forms.GroupBox()
        Me.pbSecure = New System.Windows.Forms.PictureBox()
        Me.headerLeft = New System.Windows.Forms.PictureBox()
        Me.headerRight = New System.Windows.Forms.PictureBox()
        Me.btnErrorWarning = New System.Windows.Forms.Button()
        Me.trackBar = New System.Windows.Forms.TrackBar()
        Me.lblSpeed = New System.Windows.Forms.Label()
        Me.headerMiddle = New System.Windows.Forms.Panel()
        Me.mainStatusStrip = New System.Windows.Forms.StatusStrip()
        Me.pbTransfer = New System.Windows.Forms.ToolStripProgressBar()
        Me.lblProgress = New System.Windows.Forms.ToolStripStatusLabel()
        Me.mainSplitContainer = New System.Windows.Forms.SplitContainer()
        Me.tableLayout = New System.Windows.Forms.TableLayoutPanel()
        Me.Panel1 = New System.Windows.Forms.Panel()
        Me.panelLeft = New System.Windows.Forms.Panel()
        Me.panelMiddle = New System.Windows.Forms.Panel()
        Me.gbControl.SuspendLayout()
        Me.gbTransfer.SuspendLayout()
        CType(Me.pbSecure, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.headerLeft, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.headerRight, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.trackBar, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.headerMiddle.SuspendLayout()
        Me.mainStatusStrip.SuspendLayout()
        CType(Me.mainSplitContainer, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.mainSplitContainer.Panel1.SuspendLayout()
        Me.mainSplitContainer.Panel2.SuspendLayout()
        Me.mainSplitContainer.SuspendLayout()
        Me.tableLayout.SuspendLayout()
        Me.Panel1.SuspendLayout()
        Me.panelLeft.SuspendLayout()
        Me.panelMiddle.SuspendLayout()
        Me.SuspendLayout()
        '
        'listServer
        '
        Me.listServer.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
            Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.listServer.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.itemName, Me.itemSize, Me.itemDate})
        Me.listServer.FullRowSelect = True
        Me.listServer.HideSelection = False
        Me.listServer.Location = New System.Drawing.Point(0, 20)
        Me.listServer.MultiSelect = False
        Me.listServer.Name = "listServer"
        Me.listServer.Size = New System.Drawing.Size(314, 380)
        Me.listServer.TabIndex = 2
        Me.listServer.UseCompatibleStateImageBehavior = False
        Me.listServer.View = System.Windows.Forms.View.Details
        '
        'itemName
        '
        Me.itemName.Name = "itemName"
        Me.itemName.Text = "ItemName"
        Me.itemName.Width = 120
        '
        'itemSize
        '
        Me.itemSize.Name = "itemSize"
        Me.itemSize.Text = "Size"
        Me.itemSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right
        '
        'itemDate
        '
        Me.itemDate.Name = "itemDate"
        Me.itemDate.Text = "ItemDate"
        Me.itemDate.Width = 120
        '
        'listLocal
        '
        Me.listLocal.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
            Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.listLocal.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.columnHeader1, Me.columnHeader2, Me.columnHeader3})
        Me.listLocal.FullRowSelect = True
        Me.listLocal.HideSelection = False
        Me.listLocal.Location = New System.Drawing.Point(0, 20)
        Me.listLocal.MultiSelect = False
        Me.listLocal.Name = "listLocal"
        Me.listLocal.Size = New System.Drawing.Size(314, 429)
        Me.listLocal.TabIndex = 25
        Me.listLocal.UseCompatibleStateImageBehavior = False
        Me.listLocal.View = System.Windows.Forms.View.Details
        '
        'columnHeader1
        '
        Me.columnHeader1.Name = "columnHeader1"
        Me.columnHeader1.Text = "Name"
        Me.columnHeader1.Width = 120
        '
        'columnHeader2
        '
        Me.columnHeader2.Name = "columnHeader2"
        Me.columnHeader2.Text = "Size"
        Me.columnHeader2.TextAlign = System.Windows.Forms.HorizontalAlignment.Right
        '
        'columnHeader3
        '
        Me.columnHeader3.Name = "columnHeader3"
        Me.columnHeader3.Text = "Date"
        Me.columnHeader3.Width = 120
        '
        'tbLog
        '
        Me.tbLog.AccessibleRole = System.Windows.Forms.AccessibleRole.None
        Me.tbLog.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
            Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.tbLog.BackColor = System.Drawing.SystemColors.Control
        Me.tbLog.Cursor = System.Windows.Forms.Cursors.IBeam
        Me.tbLog.Font = New System.Drawing.Font("Lucida Console", 9.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point)
        Me.tbLog.Location = New System.Drawing.Point(0, 0)
        Me.tbLog.MaxLength = 1000000
        Me.tbLog.Name = "tbLog"
        Me.tbLog.ReadOnly = True
        Me.tbLog.Size = New System.Drawing.Size(756, 110)
        Me.tbLog.TabIndex = 8
        Me.tbLog.Text = ""
        Me.tbLog.WordWrap = False
        '
        'lblServer
        '
        Me.lblServer.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.lblServer.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point)
        Me.lblServer.Location = New System.Drawing.Point(4, 407)
        Me.lblServer.Name = "lblServer"
        Me.lblServer.Size = New System.Drawing.Size(187, 25)
        Me.lblServer.TabIndex = 9
        Me.lblServer.Text = "12345"
        '
        'lblServerDirectory
        '
        Me.lblServerDirectory.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.lblServerDirectory.BackColor = System.Drawing.SystemColors.InactiveCaption
        Me.lblServerDirectory.FlatStyle = System.Windows.Forms.FlatStyle.Popup
        Me.lblServerDirectory.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
        Me.lblServerDirectory.ForeColor = System.Drawing.SystemColors.InactiveCaptionText
        Me.lblServerDirectory.Location = New System.Drawing.Point(0, 0)
        Me.lblServerDirectory.Name = "lblServerDirectory"
        Me.lblServerDirectory.Size = New System.Drawing.Size(314, 20)
        Me.lblServerDirectory.TabIndex = 1
        Me.lblServerDirectory.Text = "/root"
        Me.lblServerDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
        '
        'lblLocal
        '
        Me.lblLocal.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.lblLocal.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point)
        Me.lblLocal.Location = New System.Drawing.Point(4, 454)
        Me.lblLocal.Name = "lblLocal"
        Me.lblLocal.Size = New System.Drawing.Size(310, 16)
        Me.lblLocal.TabIndex = 12
        Me.lblLocal.Text = "12345"
        '
        'lblLocalDirectory
        '
        Me.lblLocalDirectory.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.lblLocalDirectory.BackColor = System.Drawing.SystemColors.InactiveCaption
        Me.lblLocalDirectory.FlatStyle = System.Windows.Forms.FlatStyle.Popup
        Me.lblLocalDirectory.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
        Me.lblLocalDirectory.ForeColor = System.Drawing.SystemColors.InactiveCaptionText
        Me.lblLocalDirectory.Location = New System.Drawing.Point(0, 0)
        Me.lblLocalDirectory.Name = "lblLocalDirectory"
        Me.lblLocalDirectory.Size = New System.Drawing.Size(314, 20)
        Me.lblLocalDirectory.TabIndex = 23
        Me.lblLocalDirectory.Text = "/root"
        Me.lblLocalDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
        '
        'btnStop
        '
        Me.btnStop.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnStop.Location = New System.Drawing.Point(19, 272)
        Me.btnStop.Name = "btnStop"
        Me.btnStop.Size = New System.Drawing.Size(90, 28)
        Me.btnStop.TabIndex = 17
        Me.btnStop.Text = "Abort"
        Me.btnStop.Visible = False
        '
        'btnDelete
        '
        Me.btnDelete.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnDelete.Location = New System.Drawing.Point(19, 154)
        Me.btnDelete.Name = "btnDelete"
        Me.btnDelete.Size = New System.Drawing.Size(90, 28)
        Me.btnDelete.TabIndex = 11
        Me.btnDelete.Text = "Delete"
        '
        'btnUpload
        '
        Me.btnUpload.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnUpload.Location = New System.Drawing.Point(19, 239)
        Me.btnUpload.Name = "btnUpload"
        Me.btnUpload.Size = New System.Drawing.Size(90, 28)
        Me.btnUpload.TabIndex = 15
        Me.btnUpload.Text = "< Upload"
        '
        'btnDownload
        '
        Me.btnDownload.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnDownload.Location = New System.Drawing.Point(19, 206)
        Me.btnDownload.Name = "btnDownload"
        Me.btnDownload.Size = New System.Drawing.Size(90, 28)
        Me.btnDownload.TabIndex = 13
        Me.btnDownload.Text = "Download >"
        '
        'rbBin
        '
        Me.rbBin.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.rbBin.Location = New System.Drawing.Point(19, 20)
        Me.rbBin.Name = "rbBin"
        Me.rbBin.Size = New System.Drawing.Size(78, 24)
        Me.rbBin.TabIndex = 19
        Me.rbBin.Text = "Binary"
        '
        'rbAsc
        '
        Me.rbAsc.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.rbAsc.Location = New System.Drawing.Point(19, 46)
        Me.rbAsc.Name = "rbAsc"
        Me.rbAsc.Size = New System.Drawing.Size(82, 24)
        Me.rbAsc.TabIndex = 21
        Me.rbAsc.Text = "ASCII"
        '
        'btnRefresh
        '
        Me.btnRefresh.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnRefresh.Location = New System.Drawing.Point(19, 87)
        Me.btnRefresh.Name = "btnRefresh"
        Me.btnRefresh.Size = New System.Drawing.Size(90, 29)
        Me.btnRefresh.TabIndex = 5
        Me.btnRefresh.Text = "Refresh"
        '
        'btnMakeDir
        '
        Me.btnMakeDir.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnMakeDir.Location = New System.Drawing.Point(19, 121)
        Me.btnMakeDir.Name = "btnMakeDir"
        Me.btnMakeDir.Size = New System.Drawing.Size(90, 28)
        Me.btnMakeDir.TabIndex = 7
        Me.btnMakeDir.Text = "Create folder"
        '
        'cbDrives
        '
        Me.cbDrives.ItemHeight = 15
        Me.cbDrives.Location = New System.Drawing.Point(20, 49)
        Me.cbDrives.Name = "cbDrives"
        Me.cbDrives.Size = New System.Drawing.Size(88, 23)
        Me.cbDrives.TabIndex = 4
        '
        'btnConnect
        '
        Me.btnConnect.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.btnConnect.Location = New System.Drawing.Point(19, 20)
        Me.btnConnect.Name = "btnConnect"
        Me.btnConnect.Size = New System.Drawing.Size(90, 28)
        Me.btnConnect.TabIndex = 3
        Me.btnConnect.Text = "Connect..."
        '
        'gbControl
        '
        Me.gbControl.Anchor = System.Windows.Forms.AnchorStyles.Top
        Me.gbControl.Controls.Add(Me.btnStop)
        Me.gbControl.Controls.Add(Me.btnDelete)
        Me.gbControl.Controls.Add(Me.btnUpload)
        Me.gbControl.Controls.Add(Me.btnDownload)
        Me.gbControl.Controls.Add(Me.btnRefresh)
        Me.gbControl.Controls.Add(Me.btnMakeDir)
        Me.gbControl.Controls.Add(Me.cbDrives)
        Me.gbControl.Controls.Add(Me.btnConnect)
        Me.gbControl.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.gbControl.Location = New System.Drawing.Point(5, 4)
        Me.gbControl.Name = "gbControl"
        Me.gbControl.Size = New System.Drawing.Size(127, 323)
        Me.gbControl.TabIndex = 25
        Me.gbControl.TabStop = False
        Me.gbControl.Text = "Controls"
        '
        'gbTransfer
        '
        Me.gbTransfer.Anchor = System.Windows.Forms.AnchorStyles.Top
        Me.gbTransfer.Controls.Add(Me.rbBin)
        Me.gbTransfer.Controls.Add(Me.rbAsc)
        Me.gbTransfer.FlatStyle = System.Windows.Forms.FlatStyle.System
        Me.gbTransfer.Location = New System.Drawing.Point(5, 333)
        Me.gbTransfer.Name = "gbTransfer"
        Me.gbTransfer.Size = New System.Drawing.Size(127, 137)
        Me.gbTransfer.TabIndex = 29
        Me.gbTransfer.TabStop = False
        Me.gbTransfer.Text = "Transfer"
        '
        'pbSecure
        '
        Me.pbSecure.Image = CType(resources.GetObject("pbSecure.Image"), System.Drawing.Image)
        Me.pbSecure.Location = New System.Drawing.Point(45, 12)
        Me.pbSecure.Name = "pbSecure"
        Me.pbSecure.Size = New System.Drawing.Size(38, 39)
        Me.pbSecure.TabIndex = 29
        Me.pbSecure.TabStop = False
        Me.pbSecure.Visible = False
        '
        'headerLeft
        '
        Me.headerLeft.BackColor = System.Drawing.Color.White
        Me.headerLeft.Image = CType(resources.GetObject("headerLeft.Image"), System.Drawing.Image)
        Me.headerLeft.Location = New System.Drawing.Point(0, 0)
        Me.headerLeft.Margin = New System.Windows.Forms.Padding(0)
        Me.headerLeft.Name = "headerLeft"
        Me.headerLeft.Size = New System.Drawing.Size(470, 59)
        Me.headerLeft.TabIndex = 26
        Me.headerLeft.TabStop = False
        '
        'headerRight
        '
        Me.headerRight.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.headerRight.BackColor = System.Drawing.Color.White
        Me.headerRight.Cursor = System.Windows.Forms.Cursors.Hand
        Me.headerRight.Image = CType(resources.GetObject("headerRight.Image"), System.Drawing.Image)
        Me.headerRight.Location = New System.Drawing.Point(634, 0)
        Me.headerRight.Margin = New System.Windows.Forms.Padding(0)
        Me.headerRight.Name = "headerRight"
        Me.headerRight.Size = New System.Drawing.Size(150, 59)
        Me.headerRight.TabIndex = 28
        Me.headerRight.TabStop = False
        '
        'btnErrorWarning
        '
        Me.btnErrorWarning.Dock = System.Windows.Forms.DockStyle.Right
        Me.btnErrorWarning.FlatStyle = System.Windows.Forms.FlatStyle.Popup
        Me.btnErrorWarning.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point)
        Me.btnErrorWarning.Location = New System.Drawing.Point(759, 0)
        Me.btnErrorWarning.Name = "btnErrorWarning"
        Me.btnErrorWarning.Size = New System.Drawing.Size(25, 110)
        Me.btnErrorWarning.TabIndex = 29
        Me.btnErrorWarning.Text = "!"
        '
        'trackBar
        '
        Me.trackBar.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.trackBar.LargeChange = 10
        Me.trackBar.Location = New System.Drawing.Point(4, 434)
        Me.trackBar.Maximum = 100
        Me.trackBar.Minimum = 1
        Me.trackBar.Name = "trackBar"
        Me.trackBar.Size = New System.Drawing.Size(307, 45)
        Me.trackBar.SmallChange = 5
        Me.trackBar.TabIndex = 30
        Me.trackBar.TickFrequency = 5
        Me.trackBar.Value = 100
        '
        'lblSpeed
        '
        Me.lblSpeed.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.lblSpeed.Location = New System.Drawing.Point(197, 407)
        Me.lblSpeed.Name = "lblSpeed"
        Me.lblSpeed.Size = New System.Drawing.Size(114, 25)
        Me.lblSpeed.TabIndex = 0
        Me.lblSpeed.Text = "Speed: Unlimited"
        Me.lblSpeed.TextAlign = System.Drawing.ContentAlignment.TopRight
        '
        'headerMiddle
        '
        Me.headerMiddle.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.headerMiddle.BackColor = System.Drawing.Color.White
        Me.headerMiddle.BackgroundImage = CType(resources.GetObject("headerMiddle.BackgroundImage"), System.Drawing.Image)
        Me.headerMiddle.Controls.Add(Me.pbSecure)
        Me.headerMiddle.Location = New System.Drawing.Point(470, 0)
        Me.headerMiddle.Name = "headerMiddle"
        Me.headerMiddle.Size = New System.Drawing.Size(164, 59)
        Me.headerMiddle.TabIndex = 27
        '
        'mainStatusStrip
        '
        Me.mainStatusStrip.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.pbTransfer, Me.lblProgress})
        Me.mainStatusStrip.Location = New System.Drawing.Point(0, 656)
        Me.mainStatusStrip.Name = "mainStatusStrip"
        Me.mainStatusStrip.Size = New System.Drawing.Size(784, 25)
        Me.mainStatusStrip.TabIndex = 31
        Me.mainStatusStrip.Text = "statusStrip"
        '
        'pbTransfer
        '
        Me.pbTransfer.Name = "pbTransfer"
        Me.pbTransfer.Size = New System.Drawing.Size(192, 19)
        '
        'lblProgress
        '
        Me.lblProgress.Name = "lblProgress"
        Me.lblProgress.Size = New System.Drawing.Size(60, 20)
        Me.lblProgress.Text = "Welcome!"
        '
        'mainSplitContainer
        '
        Me.mainSplitContainer.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
            Or System.Windows.Forms.AnchorStyles.Left) _
            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.mainSplitContainer.Location = New System.Drawing.Point(0, 59)
        Me.mainSplitContainer.Name = "mainSplitContainer"
        Me.mainSplitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal
        '
        'mainSplitContainer.Panel1
        '
        Me.mainSplitContainer.Panel1.Controls.Add(Me.tableLayout)
        Me.mainSplitContainer.Panel1MinSize = 320
        '
        'mainSplitContainer.Panel2
        '
        Me.mainSplitContainer.Panel2.Controls.Add(Me.tbLog)
        Me.mainSplitContainer.Panel2.Controls.Add(Me.btnErrorWarning)
        Me.mainSplitContainer.Panel2MinSize = 30
        Me.mainSplitContainer.Size = New System.Drawing.Size(784, 597)
        Me.mainSplitContainer.SplitterDistance = 483
        Me.mainSplitContainer.TabIndex = 32
        '
        'tableLayout
        '
        Me.tableLayout.ColumnCount = 3
        Me.tableLayout.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
        Me.tableLayout.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 144.0!))
        Me.tableLayout.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
        Me.tableLayout.Controls.Add(Me.Panel1, 2, 0)
        Me.tableLayout.Controls.Add(Me.panelLeft, 0, 0)
        Me.tableLayout.Controls.Add(Me.panelMiddle, 1, 0)
        Me.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill
        Me.tableLayout.Location = New System.Drawing.Point(0, 0)
        Me.tableLayout.Name = "tableLayout"
        Me.tableLayout.RowCount = 1
        Me.tableLayout.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100.0!))
        Me.tableLayout.Size = New System.Drawing.Size(784, 483)
        Me.tableLayout.TabIndex = 31
        '
        'Panel1
        '
        Me.Panel1.Controls.Add(Me.lblLocalDirectory)
        Me.Panel1.Controls.Add(Me.lblLocal)
        Me.Panel1.Controls.Add(Me.listLocal)
        Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill
        Me.Panel1.Location = New System.Drawing.Point(467, 3)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(314, 477)
        Me.Panel1.TabIndex = 32
        '
        'panelLeft
        '
        Me.panelLeft.Controls.Add(Me.lblServerDirectory)
        Me.panelLeft.Controls.Add(Me.trackBar)
        Me.panelLeft.Controls.Add(Me.listServer)
        Me.panelLeft.Controls.Add(Me.lblServer)
        Me.panelLeft.Controls.Add(Me.lblSpeed)
        Me.panelLeft.Dock = System.Windows.Forms.DockStyle.Fill
        Me.panelLeft.Location = New System.Drawing.Point(3, 3)
        Me.panelLeft.Name = "panelLeft"
        Me.panelLeft.Size = New System.Drawing.Size(314, 477)
        Me.panelLeft.TabIndex = 31
        '
        'panelMiddle
        '
        Me.panelMiddle.Controls.Add(Me.gbTransfer)
        Me.panelMiddle.Controls.Add(Me.gbControl)
        Me.panelMiddle.Dock = System.Windows.Forms.DockStyle.Fill
        Me.panelMiddle.Location = New System.Drawing.Point(323, 3)
        Me.panelMiddle.Name = "panelMiddle"
        Me.panelMiddle.Size = New System.Drawing.Size(138, 477)
        Me.panelMiddle.TabIndex = 30
        '
        'MainForm
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(6, 16)
        Me.ClientSize = New System.Drawing.Size(784, 681)
        Me.Controls.Add(Me.mainSplitContainer)
        Me.Controls.Add(Me.headerLeft)
        Me.Controls.Add(Me.headerMiddle)
        Me.Controls.Add(Me.mainStatusStrip)
        Me.Controls.Add(Me.headerRight)
        Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
        Me.KeyPreview = True
        Me.MinimumSize = New System.Drawing.Size(690, 720)
        Me.Name = "MainForm"
        Me.Text = "Simple WinForm File Transfer Client"
        Me.gbControl.ResumeLayout(False)
        Me.gbTransfer.ResumeLayout(False)
        CType(Me.pbSecure, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.headerLeft, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.headerRight, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.trackBar, System.ComponentModel.ISupportInitialize).EndInit()
        Me.headerMiddle.ResumeLayout(False)
        Me.mainStatusStrip.ResumeLayout(False)
        Me.mainStatusStrip.PerformLayout()
        Me.mainSplitContainer.Panel1.ResumeLayout(False)
        Me.mainSplitContainer.Panel2.ResumeLayout(False)
        CType(Me.mainSplitContainer, System.ComponentModel.ISupportInitialize).EndInit()
        Me.mainSplitContainer.ResumeLayout(False)
        Me.tableLayout.ResumeLayout(False)
        Me.Panel1.ResumeLayout(False)
        Me.panelLeft.ResumeLayout(False)
        Me.panelLeft.PerformLayout()
        Me.panelMiddle.ResumeLayout(False)
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub
#End Region

    ''' <summary>
    ''' win form client starts here
    ''' </summary>
    <STAThread>
    Friend Shared Sub Main()
            ' set the trial license key
            Rebex.Licensing.Key = Rebex.Samples.TrialKey.Key


        Application.Run(New MainForm())
    End Sub

    ''' <summary>
    ''' connect/disconnect remote server
    ''' </summary>
    Private Async Sub btnConnect_Click(sender As Object, e As System.EventArgs) Handles btnConnect.Click
        If _client IsNot Nothing Then
            If _isWorking Then
                Return
            End If

            ' disconnect

            trackBar.Enabled = False
            _client.Disconnect()
            _client.Dispose()
            _client = Nothing
            lblProgress.Text = "Disconnected"
            btnConnect.Text = "Connect..."
            MakeRemoteList()
            ' clearing
            Return
        End If

        ' connection dialog

        Dim connectionDialog As New ConnectionForm(_connectionData)

        Dim result As DialogResult = connectionDialog.ShowDialog()

        _connectionData.SaveConfig()

        If result <> DialogResult.OK Then
            Return
        End If

        ' create client object
        _client = New FileTransferClient()

        ' assign the logger
        _client.LogWriter = New RichTextBoxLogWriter(tbLog, tbLog.MaxLength, _connectionData.LogLevel)

        ' set event handlers
        AddHandler _client.Traversing, New EventHandler(Of TraversingEventArgs)(AddressOf Traversing)
        AddHandler _client.TransferProgressChanged, New EventHandler(Of TransferProgressChangedEventArgs)(AddressOf TransferProgressChanged)
        AddHandler _client.DeleteProgressChanged, New EventHandler(Of DeleteProgressChangedEventArgs)(AddressOf DeleteProgressChanged)
        AddHandler _client.ProblemDetected, New EventHandler(Of ProblemDetectedEventArgs)(AddressOf ProblemDetected)

        Try
            _client.FtpPassiveMode = _connectionData.PassiveMode

            ' proxy
            If _connectionData.ProxyType <> FileTransferProxyType.None Then
                Dim credential As NetworkCredential = Nothing
                If Not String.IsNullOrEmpty(_connectionData.ProxyUser) Then
                    credential = New System.Net.NetworkCredential(_connectionData.ProxyUser, _connectionData.ProxyPassword)
                End If
                If _connectionData.FileTransferMode = FileTransferMode.Sftp Then
                    _client.Proxy = New Proxy()
                Else
                    _client.Proxy = New FtpProxy()
                End If
                _client.Proxy.AuthenticationMethod = ProxyAuthentication.Basic
                _client.Proxy.ProxyType = CType(_connectionData.ProxyType, ProxyType)
                _client.Proxy.Host = _connectionData.ProxyHost
                _client.Proxy.Port = _connectionData.ProxyPort
                _client.Proxy.Credentials = credential
            End If

            ' setup SSL server certificate verifier
            If _connectionData.FileTransferMode = FileTransferMode.FtpSslExplicit OrElse _connectionData.FileTransferMode = FileTransferMode.FtpSslImplicit Then
                AddHandler _client.ValidatingCertificate, AddressOf client_ValidatingCertificate
            End If

            If _connectionData.FileTransferMode = FileTransferMode.Sftp Then
                AddHandler _client.FingerprintCheck, AddressOf client_FingerprintCheck
            End If

            ' set preferred SSH host key algorithm 
            If _connectionData.FileTransferMode = FileTransferMode.Sftp AndAlso _connectionData.ServerKeyVerifyingMode = KeyVerifyingMode.LocalyStoredFingerprint Then
                _client.Settings.SshParameters.PreferredHostKeyAlgorithm = _connectionData.ServerKeyAlgorithm
            End If

            If _connectionData.AllowWeakSuites Then
                _client.Settings.SshParameters.EncryptionAlgorithms = SshEncryptionAlgorithm.Any
                _client.Settings.SshParameters.HostKeyAlgorithms = SshHostKeyAlgorithm.Any
                _client.Settings.SshParameters.KeyExchangeAlgorithms = SshKeyExchangeAlgorithm.Any
                _client.Settings.SshParameters.MacAlgorithms = SshMacAlgorithm.Any
                _client.Settings.SshParameters.MinimumDiffieHellmanKeySize = 512
                _client.Settings.SshParameters.MinimumRsaKeySize = 512
            End If

            If _connectionData.ClientCertificate IsNot Nothing Then
                _client.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.CreateRequestHandler(_connectionData.ClientCertificate)
            End If

            _client.Settings.SslAllowedSuites = _connectionData.AllowedSuite
            _client.Settings.SslAllowedVersions = _connectionData.TlsProtocol

            ' connect
            btnStop.Visible = True
            _isWorking = True

            Try
                Await _client.ConnectAsync(_connectionData.ServerHost, _connectionData.ServerPort, _connectionData.FileTransferMode)
            Finally
                btnStop.Visible = False
                _isWorking = False
            End Try

            ' login
            If Not _client.IsAuthenticated Then
                btnStop.Visible = True
                _isWorking = True

                Try
                    If _connectionData.UseGssApi AndAlso _connectionData.FileTransferMode = FileTransferMode.Sftp Then
                        Dim credentials As SshGssApiCredentials
                        If String.IsNullOrEmpty(_connectionData.ServerUser) Then
                            credentials = New SshGssApiCredentials()
                        Else
                            ' single sign-on
                            credentials = New SshGssApiCredentials(_connectionData.ServerUser, _connectionData.ServerPassword, _connectionData.ServerDomain)
                        End If

                        Await _client.LoginAsync(credentials)
                    Else
                        If _connectionData.PrivateKey IsNot Nothing Then
                            Await _client.LoginAsync(_connectionData.ServerUser, _connectionData.ServerPassword, _connectionData.PrivateKey)
                        ElseIf _connectionData.ClientCertificate IsNot Nothing AndAlso _connectionData.FileTransferMode = FileTransferMode.Sftp Then
                            Dim key As SshPrivateKey = Nothing
                            If _connectionData.ClientCertificate IsNot Nothing Then
                                key = New SshPrivateKey(_connectionData.ClientCertificate.LeafCertificate)
                            End If

                            Await _client.LoginAsync(_connectionData.ServerUser, _connectionData.ServerPassword, key)
                        Else
                            Await _client.LoginAsync(_connectionData.ServerUser, _connectionData.ServerPassword)
                        End If
                    End If
                Finally
                    btnStop.Visible = False
                    _isWorking = False
                End Try
            End If

            ' CCC
            If _connectionData.ClearCommandChannel AndAlso (_connectionData.FileTransferMode = FileTransferMode.FtpSslExplicit OrElse _connectionData.FileTransferMode = FileTransferMode.FtpSslImplicit) Then
                _client.Settings.ClearCommandChannel()
            End If

            trackBar.Enabled = True
            btnErrorWarning.Visible = False
            btnConnect.Text = "Disconnect"
            lblProgress.Text = "Connected"
            MakeRemoteList()
        Catch ex As Exception
            WriteToLog(ex)
            If _client IsNot Nothing Then
                _client.Dispose()
                _client = Nothing
                lblProgress.Text = "Disconnected"
            End If
        Finally
            btnStop.Visible = False
            _isWorking = False
        End Try
    End Sub

    ''' <summary>
    ''' Event handler for FileTransferClient.FingerprintCheck. Validates SFTP server keys (using a fingerprint).
    ''' </summary>
    Private Sub client_FingerprintCheck(sender As Object, e As SshFingerprintEventArgs)
        Select Case _connectionData.ServerKeyVerifyingMode
            Case KeyVerifyingMode.AcceptAnyKey
                e.Accept = True
                Exit Select

            Case KeyVerifyingMode.LocalyStoredFingerprint
                Dim fingerprint As String = e.Fingerprint.ToString(_connectionData.ServerKeyHashAlgorithm)
                If fingerprint = _connectionData.ServerKeyFingerprint Then
                    e.Accept = True
                    Exit Select
                End If

                Dim resolveMode As ResolveDialogMode
                Dim resolveMessage As String

                If Not String.IsNullOrEmpty(_connectionData.ServerKeyFingerprint) Then
                    resolveMode = ResolveDialogMode.EntryDiffer
                    resolveMessage = "Stored fingerprint does not match the server key fingerprint."
                Else
                    resolveMode = ResolveDialogMode.EntryNotFound
                    resolveMessage = "Server key is not known yet."
                End If

                ' ask user for an action, if the stored fingerprint does not match
                Dim dlg As New ResolveInvalidKeyDialog(resolveMode, resolveMessage, _connectionData.ServerKeyHashAlgorithm, _connectionData.ServerKeyAlgorithm, _connectionData.ServerKeyFingerprint, e.ServerKey.KeyAlgorithm,
                    fingerprint)

                ' a) user has not specified any solution
                If dlg.ShowDialog() <> DialogResult.OK Then
                    e.Accept = False
                    Exit Select
                End If

                ' b) user has specified a solution, that changes the current mode
                Dim mode As KeyVerifyingMode = dlg.GetChoosenMode()
                Select Case mode
                    Case KeyVerifyingMode.AcceptAnyKey
                        e.Accept = True
                        Exit Select
                    Case KeyVerifyingMode.LocalyStoredFingerprint
                        _connectionData.ServerKeyFingerprint = fingerprint
                        _connectionData.SaveConfig()
                        ' save the changed mode
                        e.Accept = True
                        Exit Select
                    Case KeyVerifyingMode.RejectKey
                        e.Accept = False
                        Exit Select
                    Case Else
                        Throw New InvalidOperationException(String.Format("Unsupported enum value '{0}'", mode))
                End Select
                Exit Select
            Case Else
                Throw New InvalidOperationException(String.Format("Unsupported KeyVerifyingMode '{0}'.", _connectionData.ServerKeyVerifyingMode))
        End Select
    End Sub

    ''' <summary>
    ''' Event handler for FileTransferClient.ValidatingCertificate. Validates FTP server certificates.
    ''' </summary>
    Private Sub client_ValidatingCertificate(sender As Object, e As SslCertificateValidationEventArgs)
        While True
            Dim rejectReason As TlsCertificateAcceptance = TlsCertificateAcceptance.Other
            Dim resolveMode As ResolveDialogMode = 0
            Dim resolveMessage As String = Nothing
            Dim showAddIssuerCaToTrustedCaStore As Boolean = False

            Select Case _connectionData.ServerCertificateVerifyingMode
                Case CertificateVerifyingMode.AcceptAnyCertificate
                    ' do nothing
                    e.Accept()
                    Return

                Case CertificateVerifyingMode.LocalyStoredThumbprint
                    If _connectionData.ServerCertificateThumbprint = e.Certificate.Thumbprint Then
                        e.Accept()
                        Return
                    End If

                    If Not String.IsNullOrEmpty(_connectionData.ServerCertificateThumbprint) Then
                        resolveMode = ResolveDialogMode.EntryDiffer
                        resolveMessage = "Certificate thumbprint does not match the stored thumbprint."
                    Else
                        resolveMode = ResolveDialogMode.EntryNotFound
                        resolveMessage = "Server certificate is not known yet."
                    End If
                    Exit Select

                Case CertificateVerifyingMode.UseWindowsInfrastructure
                    ' validate using Windows infrastructure
                    Dim res As ValidationResult = e.CertificateChain.Validate(e.ServerName, ValidationOptions.None)

                    If res.Valid Then
                        e.Accept()
                        Return
                    End If

                    resolveMode = ResolveDialogMode.EntryDiffer

                    If e.CertificateChain.RootCertificate IsNot Nothing AndAlso ((res.Status And ValidationStatus.RootNotTrusted) <> 0) Then
                        showAddIssuerCaToTrustedCaStore = True
                    End If

                    resolveMessage = GetValidationResultDescription(res)

                    rejectReason = GetRejectReason(res)
                    Exit Select
                Case Else

                    Throw New InvalidOperationException(String.Format("Unsupported VerifyingMode '{0}'.", _connectionData.ServerCertificateVerifyingMode))
            End Select

            ' ask user for an action, if the certificate is invalid
            Dim dlg As New ResolveInvalidCertficiateDialog(resolveMode, resolveMessage, e.CertificateChain, _connectionData.ServerCertificateThumbprint)

            dlg.EnableAddCertificateToCA(showAddIssuerCaToTrustedCaStore)

            If dlg.ShowDialog() <> DialogResult.OK Then
                e.Reject(rejectReason)
                Return
            End If

            ' change current mode according to selected options
            Dim choosenMode As CertificateVerifyingMode = dlg.GetChoosenMode()
            Select Case choosenMode
                Case CertificateVerifyingMode.AcceptAnyCertificate
                    e.Accept()
                    Return
                Case CertificateVerifyingMode.LocalyStoredThumbprint
                    ' store the new thumbprint
                    _connectionData.ServerCertificateVerifyingMode = choosenMode
                    _connectionData.ServerCertificateThumbprint = e.Certificate.Thumbprint
                    _connectionData.SaveConfig()
                    Exit Select
                Case CertificateVerifyingMode.UseWindowsInfrastructure
                    _connectionData.ServerCertificateVerifyingMode = choosenMode
                    _connectionData.SaveConfig()
                    Exit Select
                Case CertificateVerifyingMode.RejectCertificate
                    e.Reject(TlsCertificateAcceptance.Other)
                    Return
            End Select
        End While
    End Sub

    ''' <summary>
    ''' Converts certificate validation result to rejection reason.
    ''' </summary>
    ''' <param name="result">Certificate validation result.</param>
    ''' <returns>Reject reason.</returns>
    Private Function GetRejectReason(result As ValidationResult) As TlsCertificateAcceptance
        If (result.Status And ValidationStatus.TimeNotValid) <> 0 Then
            Return TlsCertificateAcceptance.Expired
        End If
        If (result.Status And ValidationStatus.Revoked) <> 0 Then
            Return TlsCertificateAcceptance.Revoked
        End If
        If (result.Status And (ValidationStatus.RootNotTrusted Or ValidationStatus.IncompleteChain)) <> 0 Then
            Return TlsCertificateAcceptance.UnknownAuthority
        End If
        If (result.Status And (ValidationStatus.Malformed Or ValidationStatus.UnknownError)) <> 0 Then
            Return TlsCertificateAcceptance.Other
        End If
        Return TlsCertificateAcceptance.Bad
    End Function

    ''' <summary>
    ''' Constructs a human-readable string describing the certificate validation result.
    ''' </summary>
    ''' <param name="result">Certificate validation result.</param>
    ''' <returns>Validation result description.</returns>
    Private Shared Function GetValidationResultDescription(result As ValidationResult) As String
        Dim sb As New StringBuilder()
        Dim status As ValidationStatus = result.Status
        Dim values As ValidationStatus() = DirectCast([Enum].GetValues(GetType(ValidationStatus)), ValidationStatus())

        For i As Integer = 0 To values.Length - 1
            If (status And values(i)) = 0 Then
                Continue For
            End If

            status = status Xor values(i)
            Dim problem As String

            Select Case values(i)
                Case ValidationStatus.TimeNotValid
                    problem = "Server certificate has expired or is not valid yet."
                    Exit Select
                Case ValidationStatus.Revoked
                    problem = "Server certificate has been revoked."
                    Exit Select
                Case ValidationStatus.RootNotTrusted
                    problem = "Server certificate was issued by an untrusted authority."
                    Exit Select
                Case ValidationStatus.IncompleteChain
                    problem = "Server certificate does not chain up to a trusted root authority."
                    Exit Select
                Case ValidationStatus.Malformed
                    problem = "Server certificate is malformed."
                    Exit Select
                Case ValidationStatus.CnNotMatch
                    problem = "Server hostname does not match the certificate."
                    Exit Select
                Case ValidationStatus.UnknownError
                    problem = String.Format("Error {0:x} encountered while validating server's certificate.", result.NativeErrorCode)
                    Exit Select
                Case Else
                    problem = values(i).ToString()
                    Exit Select
            End Select

            sb.AppendFormat("{0}" & vbCr & vbLf, problem)
        Next
        Return sb.ToString()
    End Function

    ''' <summary>
    ''' disconnect on exit
    ''' </summary>
    Private Sub MainForm_Closing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If _client IsNot Nothing Then
            _client.Dispose()
        End If
    End Sub

    ''' <summary>
    ''' CWD or GET file command on server side
    ''' </summary>
    Private Sub ListServerClick()
        Try
            If listServer.Items.Count < 1 Then
                Return
            End If

            If listServer.SelectedItems.Count < 1 Then
                listServer.Items(0).Selected = True
            End If

            listServer.Focus()

            ' client state test

            If _isWorking Then
                Return
            End If

            Dim index As Integer = listServer.SelectedIndices(0)
            Dim item As ListViewItem = listServer.SelectedItems(0)

            If index >= _serverDirs Then
                ' GET file

                DownloadFiles(item.Text, _localPath)
            Else
                ' CWD

                Dim directory As String
                If index = 0 Then
                    directory = ".."
                Else
                    directory = item.Text
                End If

                _client.ChangeDirectory(directory)

                MakeRemoteList()
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    Private Sub listServer_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles listServer.KeyPress
        If e.KeyChar = ControlChars.Cr Then
            ListServerClick()
            listServer.Focus()
        End If
    End Sub

    Private Sub listServer_DoubleClick(sender As Object, e As System.EventArgs) Handles listServer.DoubleClick
        ListServerClick()
        listServer.Focus()
    End Sub

    ''' <summary>
    ''' change drive letter
    ''' </summary>
    Private Sub cbDrives_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles cbDrives.SelectedIndexChanged
        Try
            _localPath = cbDrives.SelectedItem.ToString()
            MakeLocalList()
        Catch ex As Exception
            WriteToLog(ex)
            listLocal.Items.Clear()
            lblLocalDirectory.Text = Nothing
            lblLocal.Text = Nothing
        End Try
    End Sub

    ''' <summary>
    ''' LCD or PUT command on local side
    ''' </summary>
    Private Sub ListLocalClick()
        Try
            If listLocal.Items.Count < 1 Then
                Return
            End If

            If listLocal.SelectedItems.Count < 1 Then
                listLocal.Items(0).Selected = True
            End If

            listLocal.Focus()

            Dim index As Integer = listLocal.SelectedIndices(0)
            Dim item As ListViewItem = listLocal.SelectedItems(0)

            If index >= _localDirs Then
                ' upload file

                UploadFiles(item.Text, _localPath)
            Else
                ' local change directory

                _localPath = Path.Combine(_localPath, item.Text)
                MakeLocalList()
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    Private Sub listLocal_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles listLocal.KeyPress
        If e.KeyChar = ControlChars.Cr Then
            ListLocalClick()
            If listLocal.Items.Count > 0 Then
                listLocal.Focus()
            End If
        End If
    End Sub

    Private Sub listLocal_DoubleClick(sender As Object, e As System.EventArgs) Handles listLocal.DoubleClick
        ListLocalClick()
        listLocal.Focus()
    End Sub

    ''' <summary>
    ''' make dir
    ''' </summary>
    Private Sub btnMakeDir_Click(sender As Object, e As System.EventArgs) Handles btnMakeDir.Click
        Try
            Dim dir As New MakeDir()

            ' REMOTE: MKDIR

            If listActive Is listServer Then
                If _isWorking Then
                    Return
                End If

                dir.ShowDialog()
                If dir.Directory IsNot Nothing Then
                    _client.CreateDirectory(dir.Directory)
                    MakeRemoteList()
                End If
            Else
                ' LOCAL: MKDIR

                dir.ShowDialog()

                If dir.Directory IsNot Nothing Then
                    Directory.CreateDirectory(Path.Combine(_localPath, dir.Directory))
                    MakeLocalList()
                End If
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    ''' <summary>
    ''' refresh listing
    ''' </summary>
    Private Sub btnRefresh_Click(sender As Object, e As System.EventArgs) Handles btnRefresh.Click
        Try
            If listActive Is listServer Then
                If _isWorking Then
                    Return
                End If

                MakeRemoteList()
            Else
                MakeLocalList()
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    Private Sub PrepareTransfer()
        ' set asc/bin transfers
        If rbBin.Checked Then
            _client.TransferType = TransferType.Binary
        Else
            _client.TransferType = TransferType.Ascii
        End If

        ' transfer
        _isWorking = True
        btnStop.Visible = True
        _problemForm.Initialize()
        _transferTime = DateTime.Now
    End Sub

    ''' <summary>
    ''' download file or directory tree
    ''' </summary>
    ''' <param name="fileName">remote file name</param>
    ''' <param name="localPath">local path</param>
    Private Async Sub DownloadFiles(fileName As String, localPath As String)
        ' client state test
        If _isWorking Then
            Return
        End If

        PrepareTransfer()

        Try
            Await _client.DownloadAsync(fileName, localPath, TraversalMode.Recursive, TransferMethod.Copy, ActionOnExistingFiles.ThrowException)
        Catch ex As Exception
            WriteToLog(ex)
        Finally
            MakeLocalList()
            TransferCompleted()
        End Try
    End Sub

    ''' <summary>
    ''' upload file or directory tree
    ''' </summary>
    ''' <param name="fileName">local file name</param>
    ''' <param name="localPath">local path</param>
    Private Async Sub UploadFiles(fileName As String, localPath As String)
        ' client state test
        If _client Is Nothing Then
            WriteToLog("Not connected!", Color.DarkOrange)
            Return
        End If
        If _isWorking Then
            Return
        End If

        localPath = Path.Combine(localPath, fileName)

        PrepareTransfer()

        Try
            Await _client.UploadAsync(localPath, ".", TraversalMode.Recursive, TransferMethod.Copy, ActionOnExistingFiles.ThrowException)
        Catch ex As Exception
            WriteToLog(ex)
        Finally
            MakeRemoteList()
            TransferCompleted()
        End Try


    End Sub

    Private Sub TransferCompleted()
        btnStop.Visible = False
        _isWorking = False
        SetProgressValue(0)
    End Sub

    ''' <summary>
    ''' show transfer status: files, bytes, time, speed
    ''' </summary>
    Private Sub ShowTransferStatus(bytesTransferred As Long, filesTransferred As Integer)
        ' unknown bytes transferred
        If bytesTransferred = 0 Then
            Return
        End If

        ' files and bytes transferred
        Dim outstring As String = String.Format("{0} file{1} ({2} byte{3}) transferred in", filesTransferred, (If(filesTransferred > 1, "s", Nothing)), bytesTransferred, (If(bytesTransferred > 1, "s", Nothing)))

        ' time spent
        Dim ts As TimeSpan = DateTime.Now - _transferTime

        ' speed
        If ts.TotalSeconds > 1 Then
            outstring += (If(ts.Days > 0, " " & ts.Days & " day" & (If(ts.Days > 1, "s", Nothing)), Nothing))
            outstring += (If(ts.Hours > 0, " " & ts.Hours & " hour" & (If(ts.Hours > 1, "s", Nothing)), Nothing))
            outstring += (If(ts.Minutes > 0, " " & ts.Minutes & " min" & (If(ts.Minutes > 1, "s", Nothing)), Nothing))
            outstring += (If(ts.Seconds > 0, " " & ts.Seconds & " sec" & (If(ts.Seconds > 1, "s", Nothing)), Nothing))
        Else
            outstring += " " & ts.TotalSeconds & " sec"
        End If

        Dim speed As Double = bytesTransferred / ts.TotalSeconds
        If speed < 1 Then
            outstring += String.Format(" at {0:F3} B/s", speed)
        ElseIf speed < 1024 Then
            outstring += String.Format(" at {0:F0} B/s", speed)
        Else
            outstring += String.Format(" at {0:F0} KB/s", speed / 1024)
        End If


        WriteToLog("> " & outstring, RichTextBoxLogWriter.COLORCOMMAND)
    End Sub

    ''' <summary>
    ''' handle download button click
    ''' </summary>
    Private Sub btnDownload_Click(sender As Object, e As System.EventArgs) Handles btnDownload.Click
        Try
            If listActive IsNot listServer Then
                Return
            End If

            If _isWorking Then
                Return
            End If

            If listServer.SelectedItems.Count > 0 Then
                DownloadFiles(listServer.SelectedItems(0).Text, _localPath)
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    ''' <summary>
    ''' handle upload button click
    ''' </summary>
    Private Sub btnUpload_Click(sender As Object, e As System.EventArgs) Handles btnUpload.Click
        Try
            If listActive Is listServer Then
                Return
            End If

            If _isWorking Then
                Return
            End If

            If listLocal.SelectedItems.Count > 0 Then
                UploadFiles(listLocal.SelectedItems(0).Text, _localPath)
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    ''' <summary>
    ''' handle delete button click
    ''' </summary>
    Private Sub btnDelete_Click(sender As Object, e As System.EventArgs) Handles btnDelete.Click
        Try
            If listActive Is listServer Then
                If _isWorking Then
                    Return
                End If

                If listServer.SelectedItems.Count > 0 Then
                    Dim index As Integer = listServer.SelectedIndices(0)
                    Dim item As ListViewItem = listServer.SelectedItems(0)

                    If index >= _serverDirs Then
                        Dim dialog As New Rebex.Samples.DeleteDialog(Rebex.Samples.DeleteDialog.DialogPrompt.DeleteFile)
                        dialog.Path = item.Text
                        dialog.ShowDialog()

                        If dialog.OK Then
                            _client.DeleteFile(item.Text)
                            MakeRemoteList()
                        End If
                    Else
                        Dim dialog As New Rebex.Samples.DeleteDialog(Rebex.Samples.DeleteDialog.DialogPrompt.DeleteDirectory)
                        dialog.Path = item.Text
                        dialog.ShowDialog()

                        If dialog.OK Then
                            _client.Delete(item.Text, TraversalMode.Recursive)
                            MakeRemoteList()
                        End If
                    End If
                End If
            Else
                If listLocal.SelectedItems.Count > 0 Then
                    Dim index As Integer = listLocal.SelectedIndices(0)
                    Dim item As ListViewItem = listLocal.SelectedItems(0)
                    Dim localItemPath As String = Path.Combine(_localPath, item.Text)

                    If index >= _localDirs Then
                        Dim dialog As New Rebex.Samples.DeleteDialog(Rebex.Samples.DeleteDialog.DialogPrompt.DeleteFile)
                        dialog.Path = item.Text
                        dialog.ShowDialog()

                        If dialog.OK Then
                            File.Delete(localItemPath)
                            MakeLocalList()
                        End If
                    Else
                        Dim dialog As New Rebex.Samples.DeleteDialog(Rebex.Samples.DeleteDialog.DialogPrompt.DeleteDirectory)
                        dialog.Path = item.Text
                        dialog.ShowDialog()

                        If dialog.OK Then
                            Directory.Delete(localItemPath, False)
                            MakeLocalList()
                        End If
                    End If
                End If
            End If
        Catch ex As Exception
            WriteToLog(ex)
        End Try
    End Sub

    ''' <summary>
    ''' activate panel on focus event
    ''' </summary>
    Private Sub listServer_Enter(sender As Object, e As System.EventArgs) Handles lblServerDirectory.Click, listServer.Enter
        listActive = listServer
        lblServerDirectory.BackColor = SystemColors.ActiveCaption
        lblServerDirectory.ForeColor = SystemColors.ActiveCaptionText
        lblLocalDirectory.BackColor = SystemColors.InactiveCaption
        lblLocalDirectory.ForeColor = SystemColors.InactiveCaptionText
    End Sub

    ''' <summary>
    ''' activate panel on focus event
    ''' </summary>
    Private Sub listLocal_Enter(sender As Object, e As System.EventArgs) Handles lblLocalDirectory.Click, listLocal.Enter
        listActive = listLocal
        lblServerDirectory.BackColor = SystemColors.InactiveCaption
        lblServerDirectory.ForeColor = SystemColors.InactiveCaptionText
        lblLocalDirectory.BackColor = SystemColors.ActiveCaption
        lblLocalDirectory.ForeColor = SystemColors.ActiveCaptionText
    End Sub

    ''' <summary>
    ''' stop transfer when something is being transferred
    ''' </summary>
    Private Sub btnStop_Click(sender As Object, e As System.EventArgs) Handles btnStop.Click
        _client.Abort()
    End Sub

    ''' <summary>
    ''' go to the url
    ''' </summary>
    Private Sub headerRight_Click(sender As Object, e As System.EventArgs) Handles headerRight.Click
        Dim info As New ProcessStartInfo(URL)
        info.UseShellExecute = True
        info.Verb = "open"
        Process.Start(info)
    End Sub

    ''' <summary>
    ''' space bar for changing panels server <-> local
    ''' </summary>
    Private Sub MainForm_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
        If e.KeyChar = Convert.ToChar(Keys.Space) Then
            If listActive Is listLocal Then
                listServer.Focus()
            Else
                listLocal.Focus()
            End If
        End If
    End Sub

    Private Sub btnErrorWarning_Click(sender As Object, e As System.EventArgs) Handles btnErrorWarning.Click
        MessageBox.Show(_exception, "Last occured error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
    End Sub

    Private Sub trackBar_Scroll(sender As Object, e As EventArgs) Handles trackBar.Scroll
        If trackBar.Value = 100 Then
            lblSpeed.Text = "Speed: Unlimited"
            _client.MaxDownloadSpeed = 0
            _client.MaxUploadSpeed = 0
        Else
            lblSpeed.Text = String.Format("Speed: {0} kB/s", trackBar.Value)
            _client.MaxDownloadSpeed = trackBar.Value
            _client.MaxUploadSpeed = trackBar.Value
        End If
    End Sub

End Class

#Region "ListViewColumnSorter"

Public Class ListViewColumnSorter
    Inherits MultiComparer
    Implements IComparer
    Public Sub New()
        MyBase.New(New FileSystemItemComparer(FileSystemItemComparerType.FileType, SortingOrder.Ascending), New FileSystemItemComparer(FileSystemItemComparerType.Name))
    End Sub

    Private Function IComparer_Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
        Dim listViewX As ListViewItem = DirectCast(x, ListViewItem)
        Dim listViewY As ListViewItem = DirectCast(y, ListViewItem)

        Dim itemX As FileSystemItem = DirectCast(listViewX.Tag, FileSystemItem)
        Dim itemY As FileSystemItem = DirectCast(listViewY.Tag, FileSystemItem)

        If itemX Is Nothing Then
            If itemY Is Nothing Then
                Return 0
            End If

            Return -1
        ElseIf itemY Is Nothing Then
            Return 1
        End If

        Return MyBase.Compare(itemX, itemY)
    End Function
End Class

#End Region
