
Public Class Form_Main

    Private DownloadFolder As String
    Private CollectedFiles_TotalSize As Long
    Private CollectedFiles_Count As Int32
    Private CollectedFolders_Count As Int32

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        '
        Load_RegularExpressions()
        LoadUserOptions()
        Load_FtpInfo()
        FTPData_To_FormControls(SelectedFtp)
        ' Ensure HTTP folder is set from FTP folder
        If txtHttpFolder.Text = "" AndAlso txtFtpFolder.Text <> "" Then
            txtHttpFolder.Text = ConvertFTP_ToArubaHTTP(txtFtpFolder.Text)
        End If
        '
        DownloadFolder = My.Application.Info.DirectoryPath & "\Downloads\"
        TestAndCreateFolder(DownloadFolder)
        '
        ToolStrip1.Renderer = New ToolStripButtonRenderer
        Text = AppTitleAndVersion("Theremino Fast FTP")
        Me.Show()
        Me.Refresh()
        ReadDirectory()
        ListView1.Select()
        Refresh()
        Opacity = 1
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        ' --------------------------------------------- Signal all operations to stop
        AbortFlag = True
        ' --------------------------------------------- Wait for operations to finish (max 3 seconds)
        Dim waitCount As Integer = 0
        While Working AndAlso waitCount < 30
            Application.DoEvents()
            System.Threading.Thread.Sleep(100)
            waitCount += 1
        End While
        ' --------------------------------------------- Save all
        SaveUserOptions()
        Save_RegularExpressions()
    End Sub

    Private Sub Form_LocationChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LocationChanged
        LimitFormPosition(Me)
    End Sub


    ' ===================================================================================
    '   MenuStrip and ToolStrip Gradients
    ' ===================================================================================
    Private Sub MenuStrip1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MenuStrip1.Paint
        Dim bounds As New Rectangle(0, 0, _
                                    MenuStrip1.Width, MenuStrip1.Height)
        Dim brush As New Drawing2D.LinearGradientBrush(bounds, _
                                                       Color.FromArgb(230, 230, 230), _
                                                       Color.FromArgb(200, 200, 200), _
                                                       Drawing2D.LinearGradientMode.Horizontal)
        e.Graphics.FillRectangle(brush, bounds)
    End Sub
    Private Sub ToolStrip1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles ToolStrip1.Paint
        Dim bounds As New Rectangle(0, 0, _
                                    ToolStrip1.Width, ToolStrip1.Height)
        Dim brush As New Drawing2D.LinearGradientBrush(bounds, _
                                                       Color.White, _
                                                       Color.FromArgb(200, 200, 200), _
                                                       Drawing2D.LinearGradientMode.Vertical)
        e.Graphics.FillRectangle(brush, bounds)
    End Sub

    ' ===================================================================================
    '   ToolStrip PressedButton color
    ' ===================================================================================
    Class ToolStripButtonRenderer
        Inherits System.Windows.Forms.ToolStripProfessionalRenderer
        Protected Overrides Sub OnRenderButtonBackground(ByVal e As ToolStripItemRenderEventArgs)
            Dim btn As ToolStripButton = CType(e.Item, ToolStripButton)
            If btn IsNot Nothing AndAlso btn.CheckOnClick AndAlso btn.Checked Then
                Dim bounds As Rectangle = New Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1)
                Dim brush As New Drawing2D.LinearGradientBrush(bounds, _
                                                               Color.Gold, _
                                                               Color.FromArgb(250, 250, 250), _
                                                               Drawing2D.LinearGradientMode.Vertical)
                e.Graphics.FillRectangle(brush, bounds)
                e.Graphics.DrawRectangle(Pens.Orange, bounds)
            Else
                MyBase.OnRenderButtonBackground(e)
            End If
        End Sub
    End Class


    ' ===================================================================================
    '  MenuStrip and ToolStrip accepting the first click
    '  If the form receives a WM_PARENTNOTIFY (528) message and is not focused 
    '  then the form is activated before to exec the message
    ' ===================================================================================
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = 528 AndAlso Not Me.Focused Then
            Me.Activate()
        End If
        MyBase.WndProc(m)
    End Sub


    ' ===================================================================================================
    '  Menu FILE
    ' ===================================================================================================
    Private Sub Menu_File_OpenDownloadFolder_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_File_OpenDownloadFolder.Click
        Process.Start("explorer", """" & DownloadFolder & """")
    End Sub
    Private Sub Menu_File_Exit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_File_Exit.Click
        Me.Close()
    End Sub

    ' ===================================================================================================
    '  Menu EDIT
    ' ===================================================================================================
    Private Sub Menu_Edit_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles Menu_Edit.DropDownOpening
        '
        ' --------------------------------------------------------------------- enable disable COPY
        If ListView1.SelectedItems.Count > 0 Then
            Menu_Edit_Copy.Enabled = True
            Menu_Edit_Download.Enabled = True
            Menu_Edit_Delete.Enabled = True
            Menu_Edit_Rename.Enabled = True
            ContextMenu_Properties.Enabled = True
        Else
            Menu_Edit_Copy.Enabled = False
            Menu_Edit_Download.Enabled = False
            Menu_Edit_Delete.Enabled = False
            Menu_Edit_Rename.Enabled = False
            ContextMenu_Properties.Enabled = False
        End If
        ' --------------------------------------------------------------------- enable disable PASTE 
        If Clipboard.GetDataObject.GetDataPresent(DataFormats.FileDrop) Then
            Menu_Edit_Paste.Enabled = True
        Else
            Menu_Edit_Paste.Enabled = False
        End If
    End Sub
    Private Sub Menu_Edit_Download_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Download.Click
        DownloadSelectedFilesAndFolders(DownloadFolder)
    End Sub
    Private Sub Menu_Edit_NewFolder_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_NewFolder.Click
        CreateNewFTPFolder()
        ReadDirectory()
    End Sub
    Private Sub Menu_Edit_Delete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Delete.Click
        DeleteSelectedFilesAndFolders()
    End Sub
    Private Sub Menu_Edit_Rename_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Rename.Click
        If ListView1.SelectedItems.Count = 1 Then
            ListView1.SelectedItems(0).BeginEdit()
        End If
    End Sub
    Private Sub Menu_Edit_Copy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Copy.Click
        If Not Working Then
            CopyToClipboard()
        End If
    End Sub
    Private Sub Menu_Edit_Paste_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Paste.Click
        If Not Working Then
            PasteFromClipBoard()
        End If
    End Sub
    Private Sub Menu_Edit_SelectAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_SelectAll.Click
        For Each item As ListViewItem In ListView1.Items
            item.Selected = True
        Next
    End Sub
    Private Sub Menu_Edit_ReloadDirectory_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_ReloadDirectory.Click
        ReadDirectory()
    End Sub
    Private Sub Menu_Edit_Properties_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Edit_Properties.Click
        ShowProperties()
    End Sub


    ' ===================================================================================================
    '  Menu Server
    ' ===================================================================================================
    Private Sub Menu_Server_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles Menu_Server.DropDownOpening
        Load_FtpInfo()
    End Sub
    Private Sub Menu_Server_SelectFTPData_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles Menu_Server_SelectFTPData.DropDownOpening
        Menu_Server_SelectFTPData.DropDownItems.Clear()
        Dim tsmi As ToolStripMenuItem
        For Each fi As FtpInfo_Struct In FtpInfo
            tsmi = New ToolStripMenuItem(fi.FTP_Folder, _
                                         Nothing, _
                                         New EventHandler(AddressOf mnuMenu_SelectFTP_Subitem_Click))

            Menu_Server_SelectFTPData.DropDownItems.Add(tsmi)
        Next
    End Sub
    Private Sub mnuMenu_SelectFTP_Subitem_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        For i As Int32 = 0 To FtpInfo.Count - 1
            If FtpInfo(i).FTP_Folder = sender.ToString Then
                SelectedFtp = i
                FTPData_To_FormControls(SelectedFtp)
                ReadDirectory()
                ListView1.Select()
            End If
        Next
    End Sub
    Private Sub Menu_Server_StoreFTPData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Server_StoreFTPData.Click
        If txtFtpFolder.Text <> "" And Not txtFtpFolder.Text.EndsWith("/") Then txtFtpFolder.Text &= "/"
        If txtHttpFolder.Text <> "" And Not txtHttpFolder.Text.EndsWith("/") Then txtHttpFolder.Text &= "/"
        StoreFTPData()
    End Sub
    Private Sub Menu_Server_OpenFTPFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Server_OpenFTPFile.Click
        Shell("notepad " & My.Application.Info.DirectoryPath & "\FtpInfo.txt", AppWinStyle.NormalFocus)
    End Sub
    Private Sub Menu_Server_DeleteFTP_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles Menu_Server_DeleteFTP.DropDownOpening
        Menu_Server_DeleteFTP.DropDownItems.Clear()
        Dim tsmi As ToolStripMenuItem
        For Each fi As FtpInfo_Struct In FtpInfo
            tsmi = New ToolStripMenuItem(fi.FTP_Folder, _
                                         Nothing, _
                                         New EventHandler(AddressOf mnuMenu_DeleteFTP_Subitem_Click))

            Menu_Server_DeleteFTP.DropDownItems.Add(tsmi)
        Next
    End Sub
    Private Sub mnuMenu_DeleteFTP_Subitem_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        For i As Int32 = 0 To FtpInfo.Count - 1
            If FtpInfo(i).FTP_Folder = sender.ToString Then
                If MsgBox("Delete selected FTP info ?", _
                           MsgBoxStyle.Question Or MsgBoxStyle.OkCancel, "Delete") = MsgBoxResult.Ok Then
                    DeleteFtpInfo(i)
                    StoreFTPData()
                    If SelectedFtp > i Then SelectedFtp -= 1
                End If
                Exit For
            End If
        Next
    End Sub
    Private Sub Menu_Server_ClearPrivateData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Server_ClearPrivateData.Click
        If MsgBox("About to deleting all UserNames and Passwords !" & vbCr & vbCr & _
                  " ARE YOU SHURE ?", _
                   MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel, "Delete private data") = MsgBoxResult.Ok Then
            txtUserName.Text = ""
            txtPassword.Text = ""
            ClearPrivateData()
            StoreFTPData()
            ReadDirectory()
            ListView1.Select()
        End If
    End Sub
    Private Sub Menu_Server_ClearAllFTPInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Server_ClearAllFTPInfo.Click
        If MsgBox("About to deleting all FTP info !" & vbCr & vbCr & _
                  " ARE YOU SHURE ?", _
                   MsgBoxStyle.Critical Or MsgBoxStyle.OkCancel, "Delete private data") = MsgBoxResult.Ok Then
            txtUserName.Text = ""
            txtPassword.Text = ""
            txtFtpFolder.Text = ""
            txtHttpFolder.Text = ""
            ClearPrivateData()
            ReDim FtpInfo(-1)
            StoreFTPData()
            ReadDirectory()
            ListView1.Select()
        End If
    End Sub

    ' ===================================================================================================
    '  Menu HELP
    ' ===================================================================================================
    Private Sub Menu_Help_Help_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Help_Help.Click
        Form_Help.Show()
    End Sub
    Private Sub Menu_Help_About_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Menu_Help_About.Click
        Form_About.ShowDialog()
    End Sub



    ' ===================================================================================================
    '  ContextMenuStrip
    ' ===================================================================================================
    Private Sub ListView1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Right Then
            ContextMenuStrip1.Show(ListView1, e.Location)
        End If
    End Sub
    Private Sub ContextMenuStrip1_Opening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
        '
        ' --------------------------------------------------------------------- enable disable RENAME
        If ListView1.SelectedItems.Count = 1 Then
            If ListView1.SelectedItems(0).Text <> ".." Then
                ContextMenu_Rename.Enabled = True
                ContextMenu_Copy.Enabled = True
                ContextMenu_CopyFullHTTPPathToClipboard.Enabled = True
                ContextMenu_Properties.Enabled = True
            Else
                ContextMenu_Rename.Enabled = False
                ContextMenu_Copy.Enabled = False
                ContextMenu_CopyFullHTTPPathToClipboard.Enabled = False
                ContextMenu_Properties.Enabled = False
            End If
        Else
            ContextMenu_Copy.Enabled = True
            ContextMenu_Rename.Enabled = False
            ContextMenu_CopyFullHTTPPathToClipboard.Enabled = False
            ContextMenu_Properties.Enabled = True
        End If
        '
        ' --------------------------------------------------------------------- enable disable PASTE 
        If Clipboard.GetDataObject.GetDataPresent(DataFormats.FileDrop) Then
            ContextMenu_Paste.Enabled = True
        Else
            ContextMenu_Paste.Enabled = False
        End If
    End Sub
    Private Sub ContextMenu_Download_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Download.Click
        DownloadSelectedFilesAndFolders(DownloadFolder)
    End Sub
    Private Sub ContextMenu_NewFolder_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_NewFolder.Click
        CreateNewFTPFolder()
    End Sub
    Private Sub ContextMenu_Delete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Delete.Click
        DeleteSelectedFilesAndFolders()
    End Sub
    Private Sub ContextMenu_Rename_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Rename.Click
        ListView1.SelectedItems(0).BeginEdit()
    End Sub
    Private Sub ContextMenu_Copy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Copy.Click
        If Not Working Then
            CopyToClipboard()
        End If
    End Sub
    Private Sub ContextMenu_Paste_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Paste.Click
        If Not Working Then
            PasteFromClipBoard()
        End If
    End Sub
    Private Sub ContextMenu_CopyFullHTTPPathToClipboard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_CopyFullHTTPPathToClipboard.Click
        If ListView1.SelectedItems.Count = 0 Then Exit Sub
        '
        Dim item As ListViewItem = ListView1.SelectedItems(0)
        Dim ftpPath As String = txtFtpFolder.Text & item.Text

        ' --------------------------------------------------------------------- Convert to HTTP
        Dim httpPath As String = ftpPath.Replace("ftp://", "https://")
        ' Replace ftp.theremino.com with www.theremino.com
        If httpPath.Contains("ftp.") Then
            httpPath = httpPath.Replace("ftp.", "www.")
        End If
        ' --------------------------------------------------------------------- Remove the extra "/www." from the path (if present)
        '                                                            Example: https://www.theremino.com/www.theremino.com/uploads/ 
        '                                                         Changed to: https://www.theremino.com/uploads/
        If httpPath.Contains("/www.") Then
            Dim startIndex As Integer = httpPath.IndexOf("/www.")
            Dim endIndex As Integer = httpPath.IndexOf("/", startIndex + 5)
            If endIndex > startIndex Then
                httpPath = httpPath.Remove(startIndex, endIndex - startIndex)
            End If
        End If
        '
        Clipboard.SetDataObject(New DataObject(DataFormats.Text, httpPath), True)
    End Sub
    Private Sub ContextMenu_Properties_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContextMenu_Properties.Click
        ShowProperties()
    End Sub


    ' ===================================================================================================
    '  TextBox and Buttons events
    ' ===================================================================================================
    Private Sub txtFtpFolder_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtFtpFolder.KeyDown
        If e.KeyCode = Keys.Enter Then
            ReadDirectory()
        End If
    End Sub
    Private Sub txtFtpFolder_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtFtpFolder.TextChanged
        If CheckBox_AutoHttp.Checked Then
            txtHttpFolder.Text = ConvertFTP_ToArubaHTTP(txtFtpFolder.Text)
        End If
    End Sub
    Private Sub Button_Break_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Break.Click
        AbortFlag = True
    End Sub
    Private Sub Button_Break_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button_Break.MouseEnter
        Application.UseWaitCursor = False
        Cursor = Cursors.Arrow
    End Sub
    Private Sub Button_Break_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button_Break.MouseLeave
        If Working Then Application.UseWaitCursor = True
        Cursor = Cursors.Default
    End Sub
    Private Sub Button_HttpDownload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_HttpDownload.Click
        HttpDownload_SelectedFilesAndFolders()
    End Sub

    ' ===================================================================================================
    '  TOOL STRIP
    ' ===================================================================================================
    Private Sub ToolStripButton_UP_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton_UP.Click
        Dim s As String = RemoveLastFolderFromUrl(txtFtpFolder.Text)
        If s.Length > 6 Then
            txtFtpFolder.Text = s
            ReadDirectory()
        End If
        ToolStripButton_UP.Checked = False
    End Sub


    ' ===================================================================================================
    '  ListView
    ' ===================================================================================================
    Private Sub ListView1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListView1.DoubleClick
        If ListView1.SelectedItems.Count <= 0 Then Exit Sub
        Dim i As ListViewItem = ListView1.SelectedItems(0)
        '
        If IsDirectory(i) Then
            txtFtpFolder.Text = txtFtpFolder.Text & i.Text & "/"

            ' ----------------------------------------------------------------------
            ' When we are in the provider root and select a different site
            ' we have ftp://ftp.xxxx.com/yyyy.../  (whith yyyy different from xxxx)
            ' ----------------------------------------------------------------------
            ' Example 1: ftp://ftp.xxxx.com/www.yyyy.com/
            ' Example 2: ftp://ftp.xxxx.com/yyyy.com/
            ' If yyyy <> xxxx then take "yyyy" and copy it in place of "xxxx"
            ' ----------------------------------------------------------------------
            If txtFtpFolder.Text.StartsWith("ftp://ftp.") Then
                ' Find the first slash after ftp://ftp.
                Dim startPos As Integer = 10 ' Length of "ftp://ftp."
                Dim firstSlash As Integer = txtFtpFolder.Text.IndexOf("/", startPos)

                If firstSlash > startPos Then
                    ' Extract current domain (xxxx)
                    Dim currentDomain As String = txtFtpFolder.Text.Substring(startPos, firstSlash - startPos)

                    ' Find the next slash after the first slash to extract the folder name
                    Dim secondSlash As Integer = txtFtpFolder.Text.IndexOf("/", firstSlash + 1)
                    If secondSlash > firstSlash + 1 Then
                        ' Extract the folder name (yyyy or www.yyyy)
                        Dim folderName As String = txtFtpFolder.Text.Substring(firstSlash + 1, secondSlash - firstSlash - 1)

                        ' Extract yyyy from the folder name (remove "www." if present)
                        Dim newDomain As String = folderName
                        If folderName.StartsWith("www.") Then
                            newDomain = folderName.Substring(4)
                        End If

                        ' If the new domain is different from the current domain, replace it
                        If newDomain <> currentDomain AndAlso newDomain.Contains(".") Then
                            txtFtpFolder.Text = "ftp://ftp." & newDomain & "/" & folderName & "/"
                        End If
                    End If
                End If
            End If

            ReadDirectory()
        Else
            DownloadSelectedFilesAndFolders(DownloadFolder)
        End If
    End Sub


    Private Function IsDirectory(ByVal item As ListViewItem) As Boolean
        If item.Text = ".." Then
            Return True
        Else
            Return item.SubItems(2).Text = "dir"
        End If
    End Function
    Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles ListView1.ColumnClick
        Sort_ListViewColumn(ListView1, e.Column)
    End Sub


    ' ===================================================================================================
    '  Restore textbox Copy and Paste shorcuts  ( earned by menu shortcuts ) 
    ' ===================================================================================================
    Private Sub text_boxes_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtUserName.GotFocus, _
                                                                                                 txtPassword.GotFocus, _
                                                                                                 txtFtpFolder.GotFocus, _
                                                                                                 txtHttpFolder.GotFocus
        MenuShortcuts_Remove()
    End Sub
    Private Sub text_boxes_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtUserName.LostFocus, _
                                                                                                  txtPassword.LostFocus, _
                                                                                                  txtFtpFolder.LostFocus, _
                                                                                                  txtHttpFolder.LostFocus
        MenuShortcuts_Restore()
    End Sub
    Private Sub RestoreTextBoxCopyAndPaste(ByVal tb As TextBox)
        If My.Computer.Keyboard.CtrlKeyDown Then
            If Key(Keys.C) Then tb.Copy()
            If Key(Keys.V) Then tb.Paste()
        End If
    End Sub
    Private Sub MenuShortcuts_Remove()
        Menu_Edit_Copy.ShortcutKeys = Keys.None
        Menu_Edit_Paste.ShortcutKeys = Keys.None
    End Sub
    Private Sub MenuShortcuts_Restore()
        Menu_Edit_Copy.ShortcutKeys = Keys.Control Or Keys.C
        Menu_Edit_Paste.ShortcutKeys = Keys.Control Or Keys.V
    End Sub


    ' ===================================================================================================
    '  EDIT ListView1 labels 
    ' ===================================================================================================
    Private ListView1_EditingLabel As Boolean = False
    Private Sub ListView1_BeforeLabelEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.LabelEditEventArgs) Handles ListView1.BeforeLabelEdit
        MenuShortcuts_Remove
        ListView1_EditingLabel = True
    End Sub
    Private Sub ListView1_AfterLabelEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.LabelEditEventArgs) Handles ListView1.AfterLabelEdit
        If e.Label <> Nothing Then
            FTP_RenameFile(txtFtpFolder.Text & ListView1.Items(e.Item).Text, _
                           e.Label, _
                           txtUserName.Text, _
                           txtPassword.Text)
            '
            ' --- "CancelEdit" correct the following error:
            ' If the item order is changed by the "Rename" then, after the "ReadDirectory",
            ' the label can be written over the wrong line 
            e.CancelEdit = True
            ' -----------------------------------------------------------------------------
            ReadDirectory()
        End If
        ListView1_EditingLabel = False
        MenuShortcuts_Restore
    End Sub


    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - ReadDirectory
    ' ===================================================================================================
    Private FileParamsList As List(Of FileParams)

    Private Sub ReadDirectory()
        Me.Refresh()
        '
        If txtFtpFolder.Text = "" Then Exit Sub
        If Not txtFtpFolder.Text.StartsWith("ftp://", StringComparison.InvariantCultureIgnoreCase) Then
            txtFtpFolder.Text = "ftp://" & txtFtpFolder.Text
        End If
        If Not txtFtpFolder.Text.EndsWith("/") Then txtFtpFolder.Text &= "/"
        '
        ' ---------------------------------------------------------------------
        FileParamsList = FTP_ListDirectoryDetails(txtFtpFolder.Text, _
                                     txtUserName.Text, _
                                     txtPassword.Text)
        '
        ' --------------------------------------------------------------------- clear
        Dim lvi As ListViewItem
        ImageList1.Images.Clear()
        ImageList1.Images.Add(FileIcons.getFolderSmallIcon())
        ListView1.Items.Clear()
        'lvi = ListView1.Items.Add("..")
        'lvi.SubItems.Add("")
        'lvi.SubItems.Add("")
        'lvi.SubItems.Add("")
        'lvi.SubItems.Add("")
        'lvi.SubItems.Add("")
        'lvi.ImageIndex = 0
        '
        ' --------------------------------------------------------------------- add folders
        For Each fp As FileParams In FileParamsList
            If fp.Type = "dir" And fp.FileName <> "." And fp.FileName <> ".." Then
                lvi = ListView1.Items.Add(fp.FileName)
                lvi.SubItems.Add("")
                lvi.SubItems.Add(fp.Type)
                lvi.SubItems.Add(fp.Modified)
                lvi.SubItems.Add(fp.permissions)
                lvi.SubItems.Add(fp.users)
                lvi.ImageIndex = 0
            End If
        Next
        ' --------------------------------------------------------------------- add files
        For Each fp As FileParams In FileParamsList
            If fp.Type <> "dir" Then
                lvi = ListView1.Items.Add(fp.FileName)
                lvi.SubItems.Add(fp.Length.ToString("###,###,###,##0"))
                lvi.SubItems.Add(fp.Type)
                lvi.SubItems.Add(fp.Modified)
                lvi.SubItems.Add(fp.permissions)
                lvi.SubItems.Add(fp.users)
                '
                Dim index As Int32 = ImageList1.Images.IndexOfKey(IO.Path.GetExtension(fp.FileName))
                If index >= 0 Then
                    lvi.ImageIndex = index
                Else
                    Dim icn As Icon = FileIcons.getSmallIcon(fp.FileName)
                    If icn IsNot Nothing Then
                        ImageList1.Images.Add(IO.Path.GetExtension(fp.FileName), icn)
                        lvi.ImageIndex = ImageList1.Images.Count - 1
                    End If
                End If
            End If
        Next
        ' --------------------------------------------------------------------- sort
        Sort_ListView_Stop()         ' Reset text of the old sorting column if any
        Sort_ListViewColumn(ListView1, 0)       ' Apply the sort
    End Sub


    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - NewFolder
    ' ===================================================================================================
    Private Sub CreateNewFTPFolder()
        ' ---------------------------------------------------- create a non-existent progressive name
        Dim index As Int32 = 0
        Dim FolderName As String
        Dim ExistingName As Boolean
        Do
            index += 1
            FolderName = "New Folder " & index.ToString
            ExistingName = False
            For Each item As ListViewItem In ListView1.Items
                If item.Text = FolderName Then
                    ExistingName = True
                    Exit For
                End If
            Next
        Loop Until Not ExistingName
        ' ---------------------------------------------------- make the FTP folder
        FTP_MakeDirectory(txtFtpFolder.Text & FolderName, _
                            txtUserName.Text, _
                            txtPassword.Text)
        ' ---------------------------------------------------- update listview
        ReadDirectory()
        ' ---------------------------------------------------- select and begin edit
        SelectListViewItem(FolderName)
        ListView1.SelectedItems(0).BeginEdit()
    End Sub


    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - Delete
    ' ===================================================================================================
    Private Sub DeleteSelectedFilesAndFolders()
        Me.Refresh()
        AbortFlag = False
        '
        ' ------------------------------------------------------------------ get selected items
        Dim items As List(Of FileParams) = GetListOfSelectedItems()
        '
        ' ------------------------------------------------------------------ collect files and folders recursively
        CollectedFiles_TotalSize = 0
        CollectedFiles_Count = 0
        CollectedFolders_Count = 0
        '
        Dim CollectedFiles As List(Of FileParams)
        CollectedFiles = New List(Of FileParams)
        CollectFilesAndFolders_To_Delete(items, CollectedFiles)
        '
        ' ------------------------------------------------------------------ delete files and folders
        Dim msg As String
        If CollectedFiles_Count = 1 Then
            msg = "Delete item: " & vbCr & vbCr & """" & ListView1.SelectedItems(0).Text & """  ?" & vbCr
        Else
            msg = "Delete " & CollectedFiles_Count.ToString & " selected items ?"
        End If
        '
        If MsgBox(msg, MsgBoxStyle.Question Or MsgBoxStyle.OkCancel, "Delete") = MsgBoxResult.Ok Then
            '
            Me.Refresh()
            '
            For Each item As FileParams In CollectedFiles

                ' -------------------------------------------------------------- check for Break and process events between files
                Application.DoEvents()
                If AbortFlag Then Exit For

                If item.Type = "dir" Then
                    If item.FileName <> ".." Then
                        FTP_RemoveDirectory(item.CompletePath, _
                                            txtUserName.Text, _
                                            txtPassword.Text)
                    End If
                Else
                    FTP_DeleteFile(item.CompletePath, _
                                   txtUserName.Text, _
                                   txtPassword.Text)
                End If
                ' --------------------------------------------------- show that the item has been processed
                If GetPath_UsingFtpScheme(item.CompletePath) = txtFtpFolder.Text Then
                    DeselectListViewItem(item.FileName)
                    ListView1.Refresh()
                End If
            Next
            '
            ReadDirectory()
        End If
        '
        AdvancementMessage("")
        pBar.Value = 0
        FinalBeep()
    End Sub

    Private Sub CollectFilesAndFolders_To_Delete(ByVal Items As List(Of FileParams), ByRef CollectedFiles As List(Of FileParams))
        '
        GroupBox_Advancement.Text = "Collecting...  Folders: " + CollectedFolders_Count.ToString + "  Files: " + CollectedFiles_Count.ToString
        GroupBox_Advancement.Refresh()
        '
        For Each item As FileParams In Items
            '
            If AbortFlag Then Exit For
            '
            If item.Type = "dir" Then
                ' --------------------------------------------------- get files and folders from this folder
                Dim NewItems As List(Of FileParams)
                NewItems = FTP_ListDirectoryDetails(item.CompletePath, _
                                                     txtUserName.Text, _
                                                     txtPassword.Text)
                ' --------------------------------------------------- recourse with new items
                CollectFilesAndFolders_To_Delete(NewItems, CollectedFiles)
                '
                ' --------------------------------------------------- add the folder
                CollectedFolders_Count += 1
                CollectedFiles.Add(item)
                '
            Else
                ' --------------------------------------------------- add the file
                CollectedFiles_Count += 1
                CollectedFiles_TotalSize += item.Length
                CollectedFiles.Add(item)
                '
            End If
        Next
    End Sub


    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - Ftp_Download
    ' ===================================================================================================
    Private Sub DownloadSelectedFilesAndFolders(ByVal DownloadFolder As String)
        Me.Refresh()
        AbortFlag = False
        '
        ' ------------------------------------------------------------------ get selected items
        Dim items As List(Of FileParams) = GetListOfSelectedItems()
        '
        ' ------------------------------------------------------------------ collect files and folders recursively
        CollectedFiles_TotalSize = 0
        CollectedFiles_Count = 0
        CollectedFolders_Count = 0
        '
        Dim CollectedFiles As List(Of FileParams)
        CollectedFiles = New List(Of FileParams)
        CollectFilesAndFolders_To_Download(items, CollectedFiles)
        '
        ' ------------------------------------------------------------------ download files and folders
        Dim index As Int32 = 0
        For Each item As FileParams In CollectedFiles

            ' -------------------------------------------------------------- check for Break and process events between files
            Application.DoEvents()
            If AbortFlag Then Exit For

            ' -------------------------------------------------------------- prepare the destination
            Dim DestinationItem As String
            DestinationItem = Replace(item.CompletePath, txtFtpFolder.Text, DownloadFolder)
            DestinationItem = Replace(DestinationItem, "/", "\")

            ' -------------------------------------------------------------- make the folder or download the file
            If item.Type = "dir" Then
                My.Computer.FileSystem.CreateDirectory(DestinationItem)
            Else
                index += 1
                AdvancementMessage("Downloading", index, CollectedFiles_Count, item.FileName)
                FTP_Download(DestinationItem, _
                              item.CompletePath, _
                              txtUserName.Text, _
                              txtPassword.Text, _
                              item.Length, _
                              AddressOf ProgressCallback)
            End If
            '
            ' --------------------------------------------------- show that the item has been processed
            If GetPath_UsingFtpScheme(item.CompletePath) = txtFtpFolder.Text Then
                DeselectListViewItem(item.FileName)
                ListView1.Refresh()
            End If
        Next
        '
        AdvancementMessage("")
        pBar.Value = 0
        FinalBeep()
    End Sub


    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - Http_Download
    ' ===================================================================================================
    Private Sub HttpDownload_SelectedFilesAndFolders()
        Me.Refresh()
        AbortFlag = False
        '
        ' ------------------------------------------------------------------ STEP 1: Check if there are selected items
        Dim items As List(Of FileParams) = GetListOfSelectedItems()
        Dim httpPath As String
        '
        ' ------------------------------------------------------------------ STEP 2: If no items selected, use HTTP folder
        If items.Count = 0 Then
            httpPath = txtHttpFolder.Text
            If String.IsNullOrEmpty(httpPath) Then
                MsgBox("HTTP folder path is empty. Please set it first.", MsgBoxStyle.Exclamation)
                Return
            End If
            '
            ' If the path does NOT end with "/", treat it as a single file download
            If Not httpPath.EndsWith("/") Then
                Dim fileName As String = IO.Path.GetFileName(httpPath)
                Dim destinationFile As String = DownloadFolder & fileName
                AdvancementMessage("Downloading HTTP", 1, 1, fileName)
                HTTP_Download(destinationFile, httpPath, AddressOf ProgressCallback)
                AdvancementMessage("")
                pBar.Value = 0
                FinalBeep()
                Return
            End If
            '
            ' If it ends with "/", download ALL items (files and folders) from the current directory
            For Each lvi As ListViewItem In ListView1.Items
                ' Skip "." and ".."
                If lvi.Text = "." OrElse lvi.Text = ".." Then Continue For

                Dim fp As New FileParams()
                fp.CompletePath = txtFtpFolder.Text & lvi.Text
                fp.FileName = lvi.Text
                fp.Length = CLng(Val(Replace(lvi.SubItems(1).Text, ".", "")))
                fp.Type = lvi.SubItems(2).Text   ' "dir" or "file"
                fp.Modified = lvi.SubItems(3).Text
                fp.permissions = lvi.SubItems(4).Text
                fp.users = lvi.SubItems(5).Text
                items.Add(fp)
            Next
            '
            If items.Count = 0 Then
                MsgBox("No items found in this directory.", MsgBoxStyle.Information)
                Return
            End If
        Else
            ' If there are selected items, use the FTP folder path as base
            httpPath = txtHttpFolder.Text
        End If
        '
        ' ------------------------------------------------------------------ STEP 3: Collect files and folders recursively
        CollectedFiles_TotalSize = 0
        CollectedFiles_Count = 0
        CollectedFolders_Count = 0
        '
        Dim CollectedFiles As List(Of FileParams) = New List(Of FileParams)
        CollectFilesAndFolders_To_Download(items, CollectedFiles)
        '
        ' ------------------------------------------------------------------ STEP 4: Download files and folders
        ' Ensure httpPath ends with "/" for replacement
        If Not httpPath.EndsWith("/") Then httpPath &= "/"
        '
        Dim SourceItem As String
        Dim DestinationItem As String
        Dim index As Int32 = 0
        Dim bUnselect As Boolean = ListView1.SelectedItems.Count > 1
        '
        For Each item As FileParams In CollectedFiles
            Application.DoEvents()
            If AbortFlag Then Exit For
            '
            SourceItem = Replace(item.CompletePath, txtFtpFolder.Text, httpPath)
            DestinationItem = Replace(item.CompletePath, txtFtpFolder.Text, DownloadFolder)
            DestinationItem = Replace(DestinationItem, "/", "\")
            '
            If item.Type = "dir" Then
                My.Computer.FileSystem.CreateDirectory(DestinationItem)
            Else
                index += 1
                AdvancementMessage("Downloading HTTP", index, CollectedFiles_Count, item.FileName)
                HTTP_Download(DestinationItem, SourceItem, AddressOf ProgressCallback)
            End If
            '
            If bUnselect Then
                If GetPath_UsingFtpScheme(item.CompletePath) = txtFtpFolder.Text Then
                    DeselectListViewItem(item.FileName)
                    ListView1.Refresh()
                End If
            End If
        Next
        '
        AdvancementMessage("")
        pBar.Value = 0
        FinalBeep()
    End Sub

    Private Sub ShowProperties()
        Me.Refresh()
        AbortFlag = False
        '
        ' ------------------------------------------------------------------ Get selected items
        Dim items As List(Of FileParams) = GetListOfSelectedItems()
        '
        ' ------------------------------------------------------------------ Collect files and folders recursively
        CollectedFiles_TotalSize = 0
        CollectedFiles_Count = 0
        CollectedFolders_Count = 0
        '
        Dim CollectedFiles As List(Of FileParams)
        CollectedFiles = New List(Of FileParams)
        CollectFilesAndFolders_To_Download(items, CollectedFiles)
        '
        ' ------------------------------------------------------------------ If only one item is selected, subtract 1 from folder count
        '                                                                    Because the selected folder is counted twice 
        '                                                                    (once as selection, once during recursion)
        If items.Count = 1 AndAlso items(0).Type = "dir" Then
            CollectedFolders_Count -= 1
        End If
        '
        ' ------------------------------------------------------------------ Restore the correct number of Folders and Files
        UpdateFolderStats(FileParamsList)
        '
        ' ------------------------------------------------------------------ Show props
        Dim s As String
        s = vbCr & "  Files:          " & CollectedFiles_Count.ToString & vbCr & vbCr
        s &= "  Folders:      " & CollectedFolders_Count.ToString & vbCr & vbCr
        s &= "  Total size:  " & CollectedFiles_TotalSize.ToString("###,###,###,##0") & "   Bytes         " & vbCr & vbCr
        MsgBox(s, MsgBoxStyle.Information, "Properties")
    End Sub



    ' ===================================================================================================
    '   CollectFilesAndFolders_To_Download
    ' ===================================================================================================

    Private Sub CollectFilesAndFolders_To_Download(ByVal Items As List(Of FileParams), ByRef CollectedFiles As List(Of FileParams))
        '
        GroupBox_Advancement.Text = "Collecting...  Folders: " + CollectedFolders_Count.ToString + "  Files: " + CollectedFiles_Count.ToString
        'GroupBox_Advancement.Refresh()
        Application.DoEvents()
        '
        For Each item As FileParams In Items
            '
            If AbortFlag Then Exit For
            '
            If item.Type = "dir" Then
                '
                ' --------------------------------------------------- add the folder
                CollectedFolders_Count += 1
                CollectedFiles.Add(item)
                '
                ' --------------------------------------------------- get files and folders from this folder
                Dim NewItems As List(Of FileParams)
                NewItems = FTP_ListDirectoryDetails(item.CompletePath, _
                                                     txtUserName.Text, _
                                                     txtPassword.Text)
                ' --------------------------------------------------- recourse with new items
                CollectFilesAndFolders_To_Download(NewItems, CollectedFiles)
                '
            Else
                ' --------------------------------------------------- add the file
                CollectedFiles_Count += 1
                CollectedFiles_TotalSize += item.Length
                CollectedFiles.Add(item)
                '
            End If
        Next

    End Sub



    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - Upload
    ' ===================================================================================================
    Private Sub UploadFilesAndFolders(ByVal files() As String)
        Me.Refresh()
        AbortFlag = False
        '
        ListView1.SelectedItems.Clear()
        ListView1.Refresh()
        ' ------------------------------------------------------------------ collect files and folders recursively
        CollectedFiles_TotalSize = 0
        CollectedFiles_Count = 0
        CollectedFolders_Count = 0
        Dim CollectedFiles(-1) As String
        CollectFilesAndFolders_To_Upload(files, CollectedFiles)

        ' ------------------------------------------------------------------ prepare the source base folder
        Dim SourceBaseFolder As String = GetPath(files(0))

        ' ------------------------------------------------------------------ upload files and folders
        Dim index As Int32 = 0
        For Each file As String In CollectedFiles

            ' -------------------------------------------------------------- check for Break and process events between files
            Application.DoEvents()
            If AbortFlag Then Exit For

            ' -------------------------------------------------------------- prepare the destination
            Dim DestinationItem As String
            DestinationItem = Replace(file, SourceBaseFolder, txtFtpFolder.Text)

            ' -------------------------------------------------------------- upload the file or make the folder
            If My.Computer.FileSystem.FileExists(file) Then
                index += 1
                AdvancementMessage("Uploading", index, CollectedFiles_Count, IO.Path.GetFileName(file))
                FTP_Upload(file, _
                           DestinationItem, _
                           txtUserName.Text, _
                           txtPassword.Text, _
                           AddressOf ProgressCallback)
            ElseIf FolderExists(file) Then
                FTP_MakeDirectory(DestinationItem, _
                                    txtUserName.Text, _
                                    txtPassword.Text)
            End If

            ' -------------------------------------------------------------- show that the item has been processed
            If GetPath_UsingFtpScheme(DestinationItem) = txtFtpFolder.Text Then
                SelectListViewItem_OrAddFileName(IO.Path.GetFileName(file))
            End If
        Next

        ReadDirectory()
        Mark_UploadedFilesAndFolders_AsSelected(files)
        AdvancementMessage("")
        pBar.Value = 0
        FinalBeep()
    End Sub

    'Friend Function FTP_to_WWW(ByVal file As String) As String
    '    file = Replace(file, "ftp://ftp", "ftp://www")
    '    Return file
    'End Function

    Friend Function GetPath_UsingFtpScheme(ByVal file As String) As String
        file = Replace(GetPath(file), "\", "/")
        file = Replace(file, "ftp:/", "ftp://")
        Return file
    End Function

    Private Sub CollectFilesAndFolders_To_Upload(ByVal Items() As String, ByRef CollectedFiles() As String)
        For Each item As String In Items
            '
            If AbortFlag Then Exit For
            '
            If FolderExists(item) Then
                ' --------------------------------------------------- add the folder
                CollectedFolders_Count += 1
                StringArray_AddNewString(CollectedFiles, item)
                '
                ' --------------------------------------------------- get files and folders from this folder
                Dim NewItems() As String
                NewItems = System.IO.Directory.GetDirectories(item, "*", IO.SearchOption.TopDirectoryOnly)
                StringArray_AddNewStringArray(NewItems, System.IO.Directory.GetFiles(item, "*", IO.SearchOption.TopDirectoryOnly))
                '
                ' --------------------------------------------------- recourse with new items
                CollectFilesAndFolders_To_Upload(NewItems, CollectedFiles)
                '
            ElseIf FileExists(item) Then
                ' --------------------------------------------------- add the file
                CollectedFiles_Count += 1
                CollectedFiles_TotalSize += FileLen(item)
                StringArray_AddNewString(CollectedFiles, item)
                '
            End If
        Next
    End Sub



    ' ===================================================================================================
    '   COMMAND EXECUTION FUNCTIONS - common functions
    ' ===================================================================================================
    Private Function GetListOfSelectedItems() As List(Of FileParams)
        GetListOfSelectedItems = New List(Of FileParams)
        For Each item As ListViewItem In ListView1.SelectedItems
            Dim newitem As FileParams
            newitem = New FileParams
            newitem.CompletePath = txtFtpFolder.Text & item.Text
            newitem.FileName = item.Text
            newitem.Length = CInt(Val(Replace(item.SubItems(1).Text, ".", "")))
            newitem.Type = item.SubItems(2).Text
            newitem.Modified = item.SubItems(3).Text
            newitem.permissions = item.SubItems(4).Text
            newitem.users = item.SubItems(5).Text
            GetListOfSelectedItems.Add(newitem)
        Next
    End Function

    Private Sub SelectListViewItem_OrAddFileName(ByVal filename As String)
        Dim item As ListViewItem
        For Each item In ListView1.Items
            If filename = item.Text Then
                item.Selected = True
                Exit Sub
            End If
        Next
        ' ------------------------------ if not exists add the filename
        item = ListView1.Items.Add(filename)
        item.Selected = True
    End Sub

    Private Sub SelectListViewItem(ByVal filename As String)
        Dim item As ListViewItem
        For Each item In ListView1.Items
            If filename = item.Text Then
                item.Selected = True
                Exit Sub
            End If
        Next
    End Sub

    Private Sub DeselectListViewItem(ByVal filename As String)
        Dim item As ListViewItem
        For Each item In ListView1.Items
            If filename = item.Text Then
                item.Selected = False
                Exit Sub
            End If
        Next
    End Sub

    Private Sub Mark_UploadedFilesAndFolders_AsSelected(ByVal files() As String)
        For Each item As ListViewItem In ListView1.Items
            item.Selected = False
            For Each f As String In files
                If IO.Path.GetFileName(f) = item.Text Then
                    item.Selected = True
                End If
            Next
        Next
    End Sub

    Private Sub ProgressCallback(ByVal params As ProgressParams)
        With params
            pBar.ForeColor = Color.Orange
            pBar.Value = Math.Min(CInt(.progress), 100)
            Label_Total.Text = Format(.fileLength / 1024, "#,0. KB")
            Label_Transferred.Text = Format(.bytesTransferred / 1024, "#,0. KB")
            Label_TotalTime.Text = FormatSeconds(.secondsTotal)
            Label_ElapsedTime.Text = FormatSeconds(.secondsElapsed)
            Label_RemainingTime.Text = FormatSeconds(.secondsRemaining)
            Label_kbpsTotal.Text = CInt(.kbps).ToString
        End With
    End Sub

    Private Sub AdvancementMessage(ByVal message As String, _
                                   Optional ByVal index As Int32 = 0, _
                                   Optional ByVal total As Int32 = 0, _
                                   Optional ByVal filename As String = "")
        If message = "" Then
            GroupBox_Advancement.Text = "Advancement info"
            pBar.Value = 0
        Else
            GroupBox_Advancement.Text = "" & index.ToString & "/" & total.ToString & " - " & message & ": " & filename

            pBar.ForeColor = Color.YellowGreen
            pBar.Value = Math.Min(CInt(index * 100 / total), 100)
        End If
    End Sub


    ' ======================================================================================================
    '  COPY and PASTE
    ' ======================================================================================================
    Private Sub CopyToClipboard()
        ' ----------------------------------------------------------------------- prepare file names
        Dim FileNames(ListView1.SelectedItems.Count - 1) As String
        For i As Int32 = 0 To ListView1.SelectedItems.Count - 1
            FileNames(i) = DownloadFolder & ListView1.SelectedItems(i).Text
        Next
        ' ----------------------------------------------------------------------- download files
        DownloadSelectedFilesAndFolders(DownloadFolder)
        ' ----------------------------------------------------------------------- put file names to the clipboard
        Dim data As IDataObject
        data = New DataObject(DataFormats.FileDrop, FileNames)
        Clipboard.SetDataObject(data, True)
        ' ----------------------------------------------------------------------- prompt the user
        MsgBox("Your downloaded files are ready in the clipboard." & vbCr & vbCr & _
               "Now you can ""Paste"" them on a Exlorer folder, the desktop or another FTP folder.", MsgBoxStyle.Information)
    End Sub
    Private Sub PasteFromClipBoard()
        Dim data As IDataObject = Clipboard.GetDataObject
        If Not data.GetDataPresent(DataFormats.FileDrop) Then Return

        Dim FileNames() As String = CType(data.GetData(DataFormats.FileDrop), String())
        UploadFilesAndFolders(FileNames)
    End Sub


    ' ===================================================================================================
    '  Drop from explorer to ListView
    ' ===================================================================================================
    Private bDropEnabled As Boolean = True
    Private Sub ListView1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListView1.DragEnter
        If e.Data.GetDataPresent(DataFormats.FileDrop) And bDropEnabled And Not Working Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If
    End Sub
    Private Sub ListView1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles ListView1.DragDrop
        AsyncUploadFileNames = DirectCast(e.Data.GetData(DataFormats.FileDrop), String())
        AsyncUploadTimer = New System.Windows.Forms.Timer
        AsyncUploadTimer.Interval = 100
        AsyncUploadTimer.Start()
    End Sub

    ' ----------------------------------------------------------------------------------------------
    '  Timer used to do a async download for dropped files - so explorer windows are not "locked"
    ' ----------------------------------------------------------------------------------------------
    Private WithEvents AsyncUploadTimer As System.Windows.Forms.Timer
    Private AsyncUploadFileNames As String()

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles AsyncUploadTimer.Tick
        AsyncUploadTimer.Stop()
        UploadFilesAndFolders(AsyncUploadFileNames)
    End Sub


    ' ===================================================================================================
    '   Start a DRAG to "Explorer windows"
    ' ===================================================================================================
    Private Sub ListView1_ItemDrag(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemDragEventArgs) Handles ListView1.ItemDrag
        '
        ' -------------------------------------------------------------- create a dummy file to copy ( for vista )
        Dim DummyFile As String
        DummyFile = DownloadFolder & "DummyFile_DummyFile_DummyFile.txt"
        File_CreateEmptyFile(DummyFile)

        ' -------------------------------------------------------------- start the drag operation
        bDropEnabled = False
        Dim res As DragDropEffects
        res = DoDragDrop(New DataObject(DataFormats.FileDrop, DummyFile), DragDropEffects.Copy)
        bDropEnabled = True

        ' -------------------------------------------------------------- delete the dummy file
        File_KillFile(DummyFile)

        ' -------------------------------------------------------------- res is always "NONE" on Vista ???
        If System.Environment.OSVersion.Version.Major < 6 Then
            If res <> DragDropEffects.Copy Then Exit Sub
        End If

        ' -------------------------------------------------------------- get the destination path
        Dim DestinationPath As String = Get_DropDestinationPath()
        If DestinationPath = "" Then
            MsgBox("Invalid drop destination path.", MsgBoxStyle.Information)
            Exit Sub
        End If

        ' -------------------------------------------------------------- if all is ok then download files
        DownloadSelectedFilesAndFolders(DestinationPath)
    End Sub


    ' =======================================================================================================
    ' TODO
    ' =======================================================================================================
    ' Toolbar UP / Find

    ' auto path "interfree / aruba / none"
    ' Disable all operations while working

    ' Abort flag - exit from all loops
    ' delete partial files

    ' passive mode ?

    ' more speed to HTTP download with "multi download splitted files"

    '    
    ' =======================================================================================================
    '  MDTM to modify a remote file's time stamp
    ' =======================================================================================================
    'Using MDTM to modify a remote file's time stamp 
    'is not endorsed by the IETF Extensions to FTP working group or any formal RFC. 

    ' Examples
    '       MFMT = "Modify Fact: Modification Time"
    '       MFCT = "Modify Fact: Creation Time"
    '       "MDTM [YYYYMMDDHHMMSS] filename.ext"
    '       "MDTM [YYYYMMDDHHMMSS] filename.ext"

    'For servers that support it (like Secure FTP Server) MDTM can be used to set the date and time. 

    'For example, the following command would set the date and time for
    ' the remote file named test.txt to be July 1, 2006 6:30:05 PM.  -->  "MDTM 20060701183005 test.txt" 

    'Some servers do not support the MDTM syntax for setting/changing file dates/times 
    '(they may say they support MDTM but it is often only in Read mode, and they can't use it to set them). 

    ' =======================================================================================================
    '   To place in "Sub FTP_Upload" ( not working )
    ' =======================================================================================================
    '' --------------------------------------------------------------------- MFMT 
    'FtpRequest = TryCast(WebRequest.Create(ServerFile), FtpWebRequest)

    ''Try
    ''    FtpRequest.Method = "MFMT 20090701085552 test.txt"
    ''Catch ex As Exception
    ''End Try

    'FtpRequest.Credentials = New NetworkCredential(UserName, Password)
    'FtpRequest.UsePassive = True
    'FtpRequest.UseBinary = True
    'FtpRequest.KeepAlive = False ' <<< close the connection when done

    '' --------------------------------------------------------------------- exec and close
    'FtpRequest.GetResponse().Close()
    ' =======================================================================================================

End Class
