WindProc.bas
上传用户:guantou168
上传日期:2015-06-25
资源大小:74k
文件大小:38k
源码类别:

Ftp服务器

开发平台:

Visual Basic

  1. Attribute VB_Name = "WindProc"
  2. Option Explicit
  3. Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
  4.   (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  5. Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
  6.   (ByVal wndrpcPrev As Long, ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  7. Public Const GWL_WNDPROC = (-4)
  8. Public intSocket As Integer
  9. Public OldWndProc As Long
  10. Public IPDot As String
  11. ' Root value for hidden window caption
  12. Public Const PROC_CAPTION = "ApartmentDemoProcessWindow"
  13. Public Const ERR_InternalStartup = &H600
  14. Public Const ERR_NoAutomation = &H601
  15. Public Const ENUM_STOP = 0
  16. Public Const ENUM_CONTINUE = 1
  17. Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
  18.    (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  19. Declare Function GetWindowThreadProcessId Lib "user32" _
  20.    (ByVal hWnd As Long, lpdwProcessId As Long) As Long
  21. Declare Function EnumThreadWindows Lib "user32" _
  22.    (ByVal dwThreadId As Long, ByVal lpfn As Long, ByVal lParam As Long) _
  23.    As Long
  24. Private mhwndVB As Long
  25. ' Window handle retrieved by EnumThreadWindows.
  26. Private mfrmProcess As New frmProcess
  27. ' Hidden form used to id main thread.
  28. Private mlngProcessID As Long
  29. ' Process ID.
  30. Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
  31. Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
  32. Private MainApp As MainApp
  33. Private Thread As Balk
  34. Private mlngTimerID As Long
  35. Sub Main()
  36.   Dim ma As MainApp
  37.   ' Borrow a window handle to use to obtain the process
  38.   '   ID (see EnumThreadWndMain call-back, below).
  39.   Call EnumThreadWindows(App.ThreadID, AddressOf EnumThreadWndMain, 0&)
  40.   If mhwndVB = 0 Then
  41.     Err.Raise ERR_InternalStartup + vbObjectError, , _
  42.              "Internal error starting thread"
  43.   Else
  44.     GetWindowThreadProcessId mhwndVB, mlngProcessID
  45.     ' The process ID makes the hidden window caption unique.
  46.     If 0 = FindWindow(vbNullString, PROC_CAPTION & CStr(mlngProcessID)) Then
  47.       ' The window wasn't found, so this is the first thread.
  48.       If App.StartMode = vbSModeStandalone Then
  49.         ' Create hidden form with unique caption.
  50.         mfrmProcess.Caption = PROC_CAPTION & CStr(mlngProcessID)
  51.         ' The Initialize event of MainApp (Instancing =
  52.         '   PublicNotCreatable) shows the main user interface.
  53.         Set ma = New MainApp
  54.         ' (Application shutdown is simpler if there is no
  55.         '   global reference to MainApp; instead, MainApp
  56.         '   should pass Me to the main user form, so that
  57.         '   the form keeps MainApp from terminating.)
  58.       Else
  59.         Err.Raise ERR_NoAutomation + vbObjectError, , _
  60.              "Application can't be started with Automation"
  61.       End If
  62.     End If
  63.   End If
  64. End Sub
  65. Public Sub SetThread(lThread As Balk)
  66.   Set Thread = lThread
  67. End Sub
  68. ' Call-back function used by EnumThreadWindows.
  69. Public Function EnumThreadWndMain(ByVal hWnd As Long, ByVal _
  70.                                   lParam As Long) As Long
  71.   ' Save the window handle.
  72.   mhwndVB = hWnd
  73.   ' The first window is the only one required.
  74.   ' Stop the iteration as soon as a window has been found.
  75.   EnumThreadWndMain = ENUM_STOP
  76. End Function
  77. ' MainApp calls this Sub in its Terminate event;
  78. '   otherwise the hidden form will keep the
  79. '   application from closing.
  80. Public Sub FreeProcessWindow()
  81.   SetWindowLong mhwndVB, GWL_WNDPROC, OldWndProc
  82.   vbWSACleanup
  83.   Unload mfrmProcess
  84.   Set mfrmProcess = Nothing
  85. End Sub
  86. Public Sub FTP_Init(lMainApp As MainApp)
  87.   Dim i As Integer
  88.   Dim hdr As String, item As String
  89.   
  90.   '--- Initialization
  91.   'an FTP command is terminated by Carriage_Return & Line_Feed
  92.   'possible sintax errors in FTP commands
  93.   sintax_error_list(0) = "200 Command Ok."
  94.   sintax_error_list(1) = "202 Command not implemented, superfluous at this site."
  95.   sintax_error_list(2) = "500 Sintax error, command unrecognized."
  96.   sintax_error_list(3) = "501 Sintax error in parameters or arguments."
  97.   sintax_error_list(4) = "502 Command not implemented."
  98.   sintax_error_list(6) = "504 Command not implemented for that parameter."
  99.   'initializes the list which contains the names,
  100.   'passwords, access rights and default directory
  101.   'recognized by the server
  102.   If LoadProfile(App.Path & "Burro.ini") Then
  103.     '
  104.   Else
  105.     'frmFTP.StatusBar.Panels(1) = "Error Loading Ini File!"
  106.   End If
  107.   
  108.   'initializes the records which contain the
  109.   'informations on the connected users
  110.   For i = 1 To MAX_N_USERS
  111.     users(i).list_index = 0
  112.  '   users(i).control_slot = INVALID_SLOT
  113.  '   users(i).data_slot = INVALID_SLOT
  114.     users(i).IP_Address = ""
  115.     users(i).Port = 0
  116.     users(i).data_representation = "A"
  117.     users(i).data_format_ctrls = "N"
  118.     users(i).data_structure = "F"
  119.     users(i).data_tx_mode = "S"
  120.     users(i).cur_dir = ""
  121.     users(i).State = Log_In_Out '0
  122.     users(i).full = False
  123.   Next
  124.  
  125.   OldWndProc = SetWindowLong(mhwndVB, GWL_WNDPROC, AddressOf WindowProc)
  126.   
  127.   Set MainApp = lMainApp
  128.  
  129.   vbWSAStartup
  130.   
  131.   'begins SERVER mode on port 21
  132.   ServerSlot = ListenForConnect(21, mhwndVB)
  133.   
  134.   If ServerSlot > 0 Then
  135.    ' frmFTP.StatusBar.Panels(1) = Description
  136.   Else
  137.   '  frmFTP.StatusBar.Panels(1) = "Error Creating Listening Socket"
  138.   End If
  139. End Sub
  140. Private Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, _
  141.                             ByVal wParam As Long, ByVal lParam As Long) As Long
  142.   Dim retf As Long
  143.   Dim SendBuffer As String, msg$
  144.   Dim lenBuffer As Integer 'send-buffer lenght
  145.   Dim RecvBuffer As String
  146.   Dim BytesRead As Integer 'receive-buffer lenght
  147.   Dim i As Integer, GoAhead As Boolean
  148.   Dim fixstr As String * 1024
  149.   Dim lct As String
  150.   Dim lcv As Integer
  151.   Dim WSAEvent As Long
  152.   Dim WSAError As Long
  153.   Dim Valid_Slot As Boolean
  154.   
  155.   Valid_Slot = False
  156.   GoAhead = True
  157.   
  158.   Select Case uMsg
  159.   Case 5150
  160.     
  161.     'ServerLog "NOTIFICATION - " & wParam & " - " & lParam & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ")
  162.     MainApp.SvrLogToScreen "NOTIFICATION - " & wParam & " - " & lParam & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ")
  163.     For i = 1 To MAX_N_USERS       'registers the slot number in the first free user record
  164.       If wParam = users(i).control_slot And users(i).full Then
  165.         Valid_Slot = True
  166.         Exit For
  167.       End If
  168.     Next
  169.     If (wParam = ServerSlot) Or (wParam = NewSlot) Or Valid_Slot Then 'event on server slot
  170.    '   frmFTP.StatusBar.Panels(1) = CStr(wParam)
  171.       WSAEvent = WSAGetSelectEvent(lParam)
  172.       WSAError = WSAGetAsyncError(lParam)
  173.       'Debug.Print "Retf = "; WSAEvent; WSAError
  174.       Select Case WSAEvent
  175.         'FD_READ    = &H1    = 1
  176.         'FD_WRITE   = &H2    = 2
  177.         'FD_OOB     = &H4    = 4
  178.         'FD_ACCEPT  = &H8    = 8
  179.         'FD_CONNECT = &H10   = 16
  180.         'FD_CLOSE   = &H20   = 32
  181.       Case FD_CONNECT
  182.         Debug.Print "FD_Connect " & wParam; lParam
  183.    '     retf = getpeername(NewSlot, SockAddr, SockAddr_Size)
  184.    '     Debug.Print "Peername = " & retf
  185.    '     Debug.Print "IPAddr1 =" & SockAddr.sin_addr
  186.    '     Debug.Print "IPPort1 =" & SockAddr.sin_port
  187.       Case FD_ACCEPT
  188.         Debug.Print "Doing FD_Accept"
  189.         SockAddr.sin_family = AF_INET
  190.         SockAddr.sin_port = 0
  191.         'SockAddr.sin_addr = 0
  192.         NewSlot = accept(ServerSlot, SockAddr, SockAddr_Size) 'try to accept new TCP connection
  193.         If NewSlot = INVALID_SOCKET Then
  194.           msg$ = "Can't accept new socket."
  195.       '    frmFTP.StatusBar.Panels(1) = msg$ & CStr(NewSlot)
  196.  
  197.         Else
  198.           Debug.Print "NewSlot OK "; NewSlot; num_users; MAX_N_USERS
  199.    '       retf = getpeername(NewSlot, SockAddr, SockAddr_Size)
  200.           IPDot = GetAscIP(SockAddr.sin_addr)
  201. 'Had to comment out the GetHostByAddress thing cause we don't do dns
  202.       '    frmFTP.StatusBar.Panels(1) = IPDot & "<>" '& vbGetHostByAddress(IPDot)
  203.           'Debug.Print "Peername = " & retf
  204.           'Debug.Print "IPAddr2 =" & SockAddr.sin_addr & " IPdot=" & IPDot
  205.           'Debug.Print "IPPort2 =" & SockAddr.sin_port & " Port:" & ntohs(SockAddr.sin_port)
  206.           If num_users >= MAX_N_USERS Then        'new service request
  207.             'the number of users exceeds the maximum allowed
  208.             SendBuffer = "421 Service not available at this time, closing control connection." & vbCrLf
  209.             lenBuffer = Len(SendBuffer)
  210.             retf = send(NewSlot, SendBuffer, lenBuffer, 0)
  211.             retf = closesocket(NewSlot)           'close connection
  212.           Else
  213.             SendBuffer = "220-Welcome to my demo Server v0.0.1!" & vbCrLf _
  214.                        & "220 This program is written in VB 5.0" & vbCrLf
  215.             lenBuffer = Len(SendBuffer)
  216.             retf = send(NewSlot, SendBuffer, lenBuffer, 0)          'send welcome message
  217.             Debug.Print "Send = " & retf
  218.             num_users = num_users + 1      'increases the number of connected users
  219.             For i = 1 To MAX_N_USERS       'registers the slot number in the first free user record
  220.               If Not users(i).full Then
  221.                 users(i).control_slot = NewSlot
  222.                 users(i).full = True
  223.                 Exit For
  224.               End If
  225.             Next
  226.           End If  'If num_users
  227.         End If  'If NewSlot
  228.       Case FD_READ
  229.         Debug.Print "Doing FD_Read"
  230.         BytesRead = recv(wParam, fixstr, 1024, 0) 'store read bytes in RecvBuffer
  231.         RecvBuffer = Left$(fixstr, BytesRead)
  232.         If InStr(RecvBuffer, vbCrLf) > 0 Then     'if received string is a command then executes it
  233.           For i = 1 To MAX_N_USERS                'event on control slots
  234.             If (wParam = users(i).control_slot) Then
  235.               retf = FTP_Cmd(i, RecvBuffer)          'tr
  236.               Exit For
  237.             End If
  238.           Next
  239.         End If
  240.       Case FD_CLOSE
  241.         Debug.Print "Doing FD_Close"
  242.         For i = 1 To MAX_N_USERS  'event on control slots
  243.           If (wParam = users(i).control_slot) Then
  244.             retf = closesocket(wParam)        'connection closed by client
  245.             users(i).control_slot = INVALID_SOCKET        'frees the user record
  246.             
  247.             Set users(i).Jenny = Nothing
  248.             users(i).full = False
  249.             'ServerLog "<" & Format$(i, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm") & " - Logged Off"
  250.             MainApp.SvrLogToScreen "<" & Format$(i, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm") & " - Logged Off"
  251.             num_users = num_users - 1
  252.             Exit For
  253.           ElseIf (wParam = users(i).data_slot) Then
  254.             retf = closesocket(wParam)        'connection closed by client
  255.             users(i).data_slot = INVALID_SOCKET   'reinitilizes data slot
  256.             users(i).State = Service_Commands '  2
  257.             Exit For
  258.           End If
  259.        Next
  260.       Case FD_WRITE
  261.         Debug.Print "Doing FD_Write"
  262.         'enables sending
  263.       End Select
  264.     End If
  265.     'Debug.Print GetWSAErrorString(WSAGetLastError)
  266.     MainApp.UsrCnt num_users
  267.   End Select
  268.   retf = CallWindowProc(OldWndProc, hWnd, uMsg, wParam, ByVal lParam)
  269.   WindowProc = retf
  270. End Function
  271. Public Function FTP_Cmd(ID_User As Integer, cmd As String) As Integer
  272.   
  273.   Dim Kwrd As String 'keyword
  274.   Dim argument(5) As String 'arguments
  275.   Dim ArgN As Long
  276.   Dim FTP_Err As Integer 'error
  277.   Dim PathName As String, Drv As String
  278.   
  279.   Dim Full_Name As String 'pathname & file name
  280.   Dim File_Len As Long 'file lenght in bytes
  281.   Dim i As Long
  282.   
  283.   Dim Ok As Integer
  284.   Dim Buffer As String
  285.   Dim DummyS As String
  286.   
  287.   'variables used during the data exchange
  288.   Dim ExecSlot As Integer
  289.   Dim NewSockAddr As SockAddr
  290.   
  291.   On Error Resume Next 'routine for error interception
  292.   
  293.   FTP_Err = sintax_ctrl(cmd, Kwrd, argument())
  294.   'log commands
  295.   'ServerLog "<" & Format$(ID_User, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ") & cmd
  296.   MainApp.SvrLogToScreen "<" & Format$(ID_User, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ") & cmd
  297.   If FTP_Err <> 0 Then
  298.     retf = send_reply(sintax_error_list(FTP_Err), ID_User)
  299.     Exit Function
  300.   End If
  301.   
  302.   Select Case UCase$(Kwrd)
  303.   Case "USER"  'USER <username>
  304.     Ok = False
  305.     Debug.Print N_RECOGNIZED_USERS;
  306.     For i = 1 To N_RECOGNIZED_USERS
  307.       'Debug.Print UserIDs.No(i).Name
  308.       'controls if the user is in the list of known users
  309.       If argument(0) = UserIDs.No(i).Name Then
  310.         'the user must enter a password but anonymous users can be accepted
  311.         If UserIDs.No(i).Name = "anonymous" Then
  312.           retf = send_reply("331 User anonymous accepted, please type your e-mail address as password.", ID_User)
  313.         Else
  314.           retf = send_reply("331 User name Ok, type in your password.", ID_User)
  315.         End If
  316.         users(ID_User).list_index = i
  317.         users(ID_User).cur_dir = UserIDs.No(i).Home
  318.         users(ID_User).State = Transfer_Parameters ' 1
  319.         Ok = True
  320.         Exit For
  321.       End If
  322.     Next
  323.     If Not Ok Then  'unknown user
  324.       retf = send_reply("530 Not logged in, user " & argument(0) & " is unknown.", ID_User)
  325.       retf = logoff(ID_User)
  326.     End If
  327.   
  328.   Case "PASS" 'PASS <password>
  329.     If users(ID_User).State = Transfer_Parameters Then '1
  330.       If LCase(UserIDs.No(users(ID_User).list_index).Name) = "anonymous" Then
  331.         'anonymous user
  332.         retf = send_reply("230 User anonymous logged in, proceed.", ID_User)
  333.         users(ID_User).State = Service_Commands ' 2
  334.         Set users(ID_User).Jenny = CreateObject("Burro.Balk")
  335.         users(ID_User).Jenny.SetUserData users(ID_User)
  336.         users(ID_User).Jenny.SetUserPermissions UserIDs.No(users(ID_User).list_index), users(ID_User).list_index
  337.         users(ID_User).Jenny.SetCallBack MainApp
  338.       Else
  339.         If argument(0) = UserIDs.No(users(ID_User).list_index).Pass Then
  340.           'correct password, the user can proceed
  341.           retf = send_reply("230 User logged in, proceed.", ID_User)
  342.           users(ID_User).State = Service_Commands ' 2
  343.           Set users(ID_User).Jenny = CreateObject("Burro.Balk")
  344.           users(ID_User).Jenny.SetUserData users(ID_User)
  345.           users(ID_User).Jenny.SetUserPermissions UserIDs.No(users(ID_User).list_index), users(ID_User).list_index
  346.           users(ID_User).Jenny.SetCallBack MainApp
  347.         Else
  348.           'wrong password, the user is disconnected
  349.           retf = send_reply("530 Not logged in, wrong password.", ID_User)
  350.           retf = logoff(ID_User)
  351.         End If
  352.       End If
  353.     Else
  354.       'the user must enter his name
  355.       retf = send_reply("503 I need your username.", ID_User)
  356.     End If
  357.   Case "QUIT": 'QUIT
  358.     retf = logoff(ID_User)
  359.   Case Else
  360. 'MainApp.SvrLogToScreen "Ftp Command Fired"
  361.     users(ID_User).Jenny.New_Cmd Kwrd, argument()
  362.   End Select
  363. End Function
  364. Public Function FTP_Cmd2() As Integer
  365.  
  366.   Dim ArgN As Long
  367.   Dim PathName As String, Drv As String
  368.   
  369.   Dim i As Long
  370.   
  371.   Dim Ok As Integer
  372.   Dim DummyS As String
  373.   
  374.   'variables used during the data exchange
  375.   Dim ExecSlot As Integer
  376.   Dim NewSockAddr As SockAddr
  377.   
  378.   Dim Full_Name As String
  379.   Dim data_representation As String * 1
  380.   Dim open_file As Integer
  381.   Dim retr_stor As Integer  '0=RETR; 1=STOR
  382.   Dim Buffer As String  'contains data to send
  383.   Dim File_Len As Long  '--- Binary mode only
  384.   Dim blocks As Long  'number of 1024 bytes blocks in file
  385.   Dim spare_bytes As Long
  386.   Dim next_block As Long  'next block to send
  387.   Dim next_byte As Long  'points to position in file of the next block to send
  388.   Dim try_again As Integer  'if try_again=true the old line is sent =Ascii mode only
  389.   Dim Dummy As String
  390.   
  391.   Dim DirFnd As Boolean
  392.   Dim error_on_data_cnt As Boolean
  393.   Dim close_data_cnt As Boolean
  394.   
  395.   On Error Resume Next 'routine for error interception
  396.   
  397.   Select Case UCase$(FTP_Command)
  398.   Case "CWD", "XCWD" 'CWD <pathname>
  399.     If users(FTP_Index).State = 2 Then
  400.       
  401.       PathName = ChkPath(FTP_Index, FTP_Args(0))
  402.       Drv = Left(PathName, 2)
  403.       
  404.       '#######################################tr####################
  405.       'controls access rights
  406.       DirFnd = False
  407.       For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  408.         If UserIDs.No(users(FTP_Index).list_index).Priv(i).Path = PathName Then
  409.         'To do drive letter permissions use this line
  410.         'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  411.           DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  412.           DirFnd = True
  413.           Exit For
  414.         End If
  415.       Next
  416.       If InStr(DummyS, "L") And DirFnd Then
  417.       
  418.       '######################################end tr#####################
  419.          ChDrive Drv
  420.          ChDir PathName
  421.          If Err.Number = 0 Then
  422.            users(FTP_Index).cur_dir = CurDir
  423.            'existing directory
  424.            retf = send_reply("250 CWD command executed.", FTP_Index)
  425.          ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  426.            'no existing directory
  427.            retf = send_reply("550 CWD command not executed: " & Error$, FTP_Index)
  428.          Else
  429.       '     frmFTP.StatusBar.Panels(1) = "Error " & CStr(Err) & " occurred."
  430.            retf = logoff(FTP_Index)
  431.            'End
  432.          End If
  433.       '#######################################tr####################
  434.       Else
  435.         retf = send_reply("550 CWD command not executed: User does not have permissions", FTP_Index)
  436.       End If
  437.       '#######################################end tr####################
  438.     Else
  439.       'user not logged in
  440.       retf = send_reply("530 User not logged in.", FTP_Index)
  441.     End If
  442.   
  443.   Case "CDUP", "XCUP": 'CDUP
  444.     If users(FTP_Index).State = 2 Then
  445.       ChDir users(FTP_Index).cur_dir
  446.       ChDir ".."
  447.       users(FTP_Index).cur_dir = CurDir
  448.       retf = send_reply("200 CDUP command executed.", FTP_Index)
  449.     Else
  450.       retf = send_reply("530 User not logged in.", FTP_Index)
  451.     End If
  452.   Case "PORT" 'PORT <host-port>
  453.     If users(FTP_Index).State = Service_Commands Then    ' 2
  454.       'opens a data connection
  455.       ExecSlot = Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
  456.       If ExecSlot < 0 Then
  457.         'error
  458.         retf = send_reply("425 Can't build data connection.", FTP_Index)
  459.       Else
  460.         NewSockAddr.sin_family = PF_INET
  461.         'remote IP address
  462.         IPLong.Byte4 = Val(FTP_Args(0))
  463.         IPLong.Byte3 = Val(FTP_Args(1))
  464.         IPLong.Byte2 = Val(FTP_Args(2))
  465.         IPLong.Byte1 = Val(FTP_Args(3))
  466.         CopyMemory i, IPLong, 4
  467.         NewSockAddr.sin_addr = i
  468.         'remote port
  469.         ArgN = Val(FTP_Args(4))
  470.         NewSockAddr.sin_port = htons(ArgN)
  471.         retf = connect(ExecSlot, NewSockAddr, 16)
  472.         If retf < 0 Then
  473.           retf = send_reply("425 Can't build data connection.", FTP_Index)
  474.         Else
  475.           retf = send_reply("200 PORT command executed.", FTP_Index)
  476.           'stores the IP-address and port number in user record
  477.           users(FTP_Index).data_slot = ExecSlot
  478.           users(FTP_Index).IP_Address = FTP_Args(0) & "." & FTP_Args(1) & "." & _
  479.                                         FTP_Args(2) & "." & FTP_Args(3)
  480.           users(FTP_Index).Port = Val(FTP_Args(4))
  481.           'ServerLog ("IP=" & users(FTP_Index).IP_Address & ":" & FTP_Args(4))
  482.           Thread.SendMessage "IP=" & users(FTP_Index).IP_Address & ":" & FTP_Args(4)
  483. '          '<state> field establishes that now is
  484. '          'possible to exec commands requiring a data connection
  485.           users(FTP_Index).State = 3
  486.           Debug.Print "data "; ExecSlot
  487.           Debug.Print "ctrl "; users(FTP_Index).control_slot
  488.         End If
  489.       End If
  490.     Else
  491.       retf = send_reply("530 User not logged in.", FTP_Index)
  492.     End If
  493. '
  494.   
  495.   Case "TYPE" 'TYPE <type-code>
  496.     If users(FTP_Index).State = 2 Then
  497.       'stores the access parameters in user record
  498.       retf = send_reply("200 TYPE command executed.", FTP_Index)
  499.       users(FTP_Index).data_representation = FTP_Args(0)
  500.       users(FTP_Index).data_format_ctrls = FTP_Args(1)
  501.     Else
  502.       retf = send_reply("530 User not logged in.", FTP_Index)
  503.     End If
  504.   
  505.   Case "STRU" 'STRU <structure-code>
  506.     If users(FTP_Index).State = 2 Then
  507.       'stores access parameters in the user record
  508.       retf = send_reply("200 STRU command executed.", FTP_Index)
  509.       users(FTP_Index).data_structure = FTP_Args(0)
  510.     Else
  511.       retf = send_reply("530 User not logged in.", FTP_Index)
  512.     End If
  513.     
  514.   Case "MODE" 'MODE <mode-code>
  515.     If users(FTP_Index).State = 2 Then
  516.       'stores access parameters in the user record
  517.       retf = send_reply("200 MODE command executed.", FTP_Index)
  518.       users(FTP_Index).data_tx_mode = FTP_Args(0)
  519.     Else
  520.       retf = send_reply("530 User not logged in.", FTP_Index)
  521.     End If
  522.   
  523.   Case "RETR" 'RETR <pathname>
  524.     On Error GoTo FileError
  525.     If users(FTP_Index).State = 3 Then
  526.       Dim Counter As Integer
  527.       Full_Name = ChkPath(FTP_Index, FTP_Args(0))
  528.         'file exist?
  529.       i = FileLen(Full_Name)
  530.       If Err.Number = 0 Then 'Yes
  531.           'controls access rights
  532.         'DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  533.         'If InStr(DummyS, "R") Then
  534.         DirFnd = False
  535.         PathName = LCase$(Left(Full_Name, InStrRev(Full_Name, "")))
  536.         For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  537.           If LCase$(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path) = PathName Then
  538.           'To do drive letter permissions use this line
  539.           'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  540.             DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  541.             DirFnd = True
  542.             Exit For
  543.           End If
  544.         Next
  545.   
  546.         If InStr(DummyS, "R") And DirFnd Then
  547.           retf = open_data_connect(FTP_Index)
  548.           
  549.           If Not open_file Then
  550.             Open Full_Name For Binary Access Read Lock Write As #FTP_Index
  551.             open_file = True
  552.           End If
  553.           Do
  554.             If users(FTP_Index).data_representation = "A" Then
  555.               If try_again Then
  556.               Else      're-send old line
  557.                 Line Input #FTP_Index, Buffer
  558.               End If
  559.               retf = send_data(Buffer & vbCrLf, FTP_Index)
  560.               If retf < 0 Then 'SOCKET_ERROR
  561.                 retf = WSAGetLastError()
  562.                 If retf = WSAEWOULDBLOCK Then
  563.                   try_again = True
  564.                 Else        'error on sending
  565.                   error_on_data_cnt = True
  566.                   close_data_cnt = True
  567.                 End If
  568.               Else
  569.                 try_again = False
  570.               End If
  571.               If EOF(FTP_Index) Then close_data_cnt = True
  572.             Else  'binary transfer
  573.               'sends file on data connection; data are sent in blocks of 1024 bytes
  574.               If next_block = 0 Then
  575.                 File_Len = LOF(FTP_Index)
  576.                 blocks = Int(File_Len / 1024)    '# of blocks
  577.                 spare_bytes = File_Len Mod 1024  '# of remaining bytes
  578.                 Buffer = String$(1024, " ")
  579.               End If
  580.               If next_block < blocks Then 'sends blocks
  581.                 Get #FTP_Index, next_byte + 1, Buffer
  582.                 retf = send_data(Buffer, FTP_Index)
  583.                 If retf < 0 Then
  584.                   retf = WSAGetLastError()
  585.                   If retf = WSAEWOULDBLOCK Then  'try again
  586.                   Else
  587.                     error_on_data_cnt = True
  588.                     close_data_cnt = True
  589.                   End If
  590.                 Else   'next block
  591.                   next_block = next_block + 1
  592.                   next_byte = next_byte + 1024
  593.                 End If
  594.               Else    'sends remaining bytes
  595.                 Buffer = String$(spare_bytes, " ")
  596.                 Get #FTP_Index, , Buffer
  597.                 retf = send_data(Buffer, FTP_Index)
  598.                 close_data_cnt = True
  599.               End If
  600.             End If
  601.           Loop Until close_data_cnt
  602.           If close_data_cnt Then  're-initialize files_info record
  603.           '  files_info(index).open_file = False
  604.           '  files_info(index).next_block = 0  'blocks count
  605.           '  files_info(index).next_byte = 0   'pointer to next block
  606.           '  files_info(index).try_again = False
  607.             
  608.             Close #FTP_Index    'close file
  609.             If error_on_data_cnt Then    'replies to user
  610.               retf = send_reply("550 RETR command not executed.", FTP_Index)
  611.             Else
  612.               retf = send_reply("226 RETR command completed.", FTP_Index)
  613.             End If
  614.             retf = close_data_connect(FTP_Index)    'close data connection
  615.           End If
  616.         Else
  617.             'the user can't retrieves files
  618.           retf = send_reply("550 You can't take this file action.", FTP_Index)
  619.           retf = close_data_connect(FTP_Index)
  620.         End If
  621.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  622.         'no existing file
  623.         retf = send_reply("550 RETR command not executed: " & Error$, FTP_Index)
  624.         retf = close_data_connect(FTP_Index)
  625.       Else
  626.         frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  627.         retf = close_data_connect(FTP_Index)
  628.         retf = logoff(FTP_Index)
  629.       End If
  630.     Else
  631.       retf = send_reply("530 User not logged in.", FTP_Index)
  632.     End If
  633. 'MsgBox App.ThreadID & " done his retr duty as " & users(FTP_Index).data_representation
  634.   Case "STOR" 'STOR <pathname>
  635.     If users(FTP_Index).State = 3 Then
  636.       Full_Name = ChkPath(FTP_Index, FTP_Args(0))
  637.       'controls access rights
  638. '      DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  639.       
  640.       DirFnd = False
  641.       PathName = LCase$(Left(Full_Name, InStrRev(Full_Name, "")))
  642.       For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  643.         If LCase$(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path) = PathName Then
  644.         'To do drive letter permissions use this line
  645.         'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  646.           DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  647.           DirFnd = True
  648.           Exit For
  649.         End If
  650.       Next
  651.   
  652.       If InStr(DummyS, "W") And DirFnd Then
  653.         If Not open_file Then
  654.           Open Full_Name For Binary Access Write Lock Read Write As #FTP_Index
  655.           open_file = True
  656.         End If
  657.         retf = open_data_connect(FTP_Index)
  658.         Do
  659.           If users(FTP_Index).data_representation = "A" Then
  660.             retf = receive_data(Buffer, FTP_Index)
  661.             If retf < 0 Then   'SOCKET_ERROR
  662.               retf = WSAGetLastError()
  663.               If retf = WSAEWOULDBLOCK Then   'try_again
  664.               Else       'error on receiving
  665.                 error_on_data_cnt = True
  666.                 close_data_cnt = True
  667.               End If
  668.             ElseIf retf = 0 Then  'connection closed by peer
  669.               close_data_cnt = True
  670.             Else 'retf > 0  write on file
  671.               Dummy$ = Left$(Buffer, retf)
  672.               Print #FTP_Index, Dummy$
  673.             End If
  674.           Else  'binary transfer
  675.             retf = receive_data(Buffer, FTP_Index)
  676.             If retf < 0 Then
  677.               retf = WSAGetLastError()
  678.               If retf = WSAEWOULDBLOCK Then  'try again
  679.               Else
  680.                 error_on_data_cnt = True
  681.                 close_data_cnt = True
  682.               End If
  683.             ElseIf retf = 0 Then     'connection closed by peer
  684.               close_data_cnt = True
  685.             Else
  686.               Dummy$ = Left$(Buffer, retf)
  687.               Put #FTP_Index, , Dummy$
  688.             End If
  689.           End If
  690.         Loop Until close_data_cnt
  691.         If close_data_cnt Then   're-initialize files_info record
  692.           'files_info(Index).open_file = False
  693.           'files_info(Index).next_block = 0 'blocks count
  694.           'files_info(Index).next_byte = 0  'pointer to next block
  695.           'files_info(Index).try_again = False
  696.           Close #FTP_Index    'close file
  697.           If error_on_data_cnt Then    'replies to user
  698.             retf = send_reply("550 STOR command not executed.", FTP_Index)
  699.           Else
  700.             retf = send_reply("226 STOR command completed.", FTP_Index)
  701.           End If
  702.           retf = close_data_connect(FTP_Index)     'closes data connection
  703.           
  704.         End If
  705.       Else
  706.         'the user can't stores files
  707.         retf = send_reply("550 You can't take this file action.", FTP_Index)
  708.         retf = close_data_connect(FTP_Index)
  709.       End If
  710.     Else
  711.       retf = send_reply("530 User not logged in.", FTP_Index)
  712.     End If
  713. MsgBox App.ThreadID & " done his stor duty as " & users(FTP_Index).data_representation
  714.   Case "RNFR"  'RNFR <pathname>
  715.     If users(FTP_Index).State = 2 Then
  716.       Full_Name = ChkPath(FTP_Index, FTP_Args(0))
  717.       'file exists?
  718.       i = FileLen(Full_Name)
  719.       If Err.Number = 0 Then 'Yes
  720.         'controls access rights
  721.         DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  722.         If InStr(DummyS, "M") Then
  723.           'The user can updates files.
  724.           'The name of file to rename is temporarily stored in the user record.
  725.           users(FTP_Index).temp_data = Full_Name
  726.           'next command must be a RNTO
  727.           users(FTP_Index).State = 6
  728.           retf = send_reply("350 ReName command expect further information.", FTP_Index)
  729.         Else
  730.           'the user can't writes on files
  731.           retf = send_reply("550 You can't take this file action.", FTP_Index)
  732.         End If
  733.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  734.         'no existing file
  735.         retf = send_reply("550 RNFR command not executed: " & Error$, FTP_Index)
  736.       Else
  737.    '     frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  738.         retf = logoff(FTP_Index)
  739.         'End
  740.       End If
  741.     Else
  742.       retf = send_reply("530 User not logged in.", FTP_Index)
  743.     End If
  744.   
  745.   Case "RNTO"  'RNTO <pathname>
  746.     If users(FTP_Index).State = 6 Then
  747.       Full_Name = ChkPath(FTP_Index, FTP_Args(0))
  748.       Name users(FTP_Index).temp_data As Full_Name
  749.       If Err.Number = 0 Then
  750.         users(FTP_Index).State = 2
  751.         'file exists
  752.         retf = send_reply("350 ReName command executed.", FTP_Index)
  753.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  754.         'no existing file
  755.         retf = send_reply("550 RNTO command not executed: " & Error$, FTP_Index)
  756.       Else
  757.   '      frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  758.         retf = logoff(FTP_Index)
  759.         'End
  760.       End If
  761.     Else
  762.       retf = send_reply("530 User not logged in.", FTP_Index)
  763.     End If
  764.     
  765.   Case "DELE"  'DELE <pathname>
  766.     If users(FTP_Index).State = 2 Then
  767.       Full_Name = ChkPath(FTP_Index, FTP_Args(0))
  768.       'controls access rights
  769.       'DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  770.       'If InStr(DummyS, "K") Then
  771.       DirFnd = False
  772.       PathName = Left(Full_Name, InStrRev(Full_Name, ""))
  773.       For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  774.         If UserIDs.No(users(FTP_Index).list_index).Priv(i).Path = PathName Then
  775.         'To do drive letter permissions use this line
  776.         'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  777.           DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  778.           DirFnd = True
  779.           Exit For
  780.         End If
  781.       Next
  782.   
  783.       If InStr(DummyS, "K") And DirFnd Then
  784.         'the user can updates files
  785.         Kill Full_Name
  786.         If Err.Number = 0 Then
  787.           'file exists
  788.           retf = send_reply("250 DELE command executed.", FTP_Index)
  789.         ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  790.           'file no exists
  791.           retf = send_reply("550 DELE command not executed: " & Error$, FTP_Index)
  792.         Else
  793.     '      frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  794.           retf = logoff(FTP_Index)
  795.           'End
  796.         End If
  797.       Else
  798.         'the user can't delete files
  799.         retf = send_reply("550 You can't take this file action.", FTP_Index)
  800.       End If
  801.     Else
  802.       retf = send_reply("530 User not logged in.", FTP_Index)
  803.     End If
  804.     
  805.   Case "RMD", "XRMD" 'RMD <pathname>
  806.     If users(FTP_Index).State = 2 Then
  807.       PathName = ChkPath(FTP_Index, FTP_Args(0))
  808.       'controls access rights
  809.       'DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  810.       'If InStr(DummyS, "D") Then
  811.       DirFnd = False
  812.       For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  813.         If UserIDs.No(users(FTP_Index).list_index).Priv(i).Path = PathName Then
  814.         'To do drive letter permissions use this line
  815.         'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  816.           DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  817.           DirFnd = True
  818.           Exit For
  819.         End If
  820.       Next
  821.   
  822.       If InStr(DummyS, "K") And DirFnd Then
  823.         'the user can updates files
  824.         Kill PathName & "*.*"
  825.         If Err.Number = 53 Or Err.Number = 708 Then Err.Number = 0 'empty directory
  826.         RmDir PathName
  827.         If Err.Number = 0 Then
  828.           'directory exists
  829.           retf = send_reply("250 RMD command executed.", FTP_Index)
  830.         ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  831.           'directory no exists
  832.           retf = send_reply("550 RMD command not executed: " & Error$, FTP_Index)
  833.         Else
  834.    '       frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  835.           retf = logoff(FTP_Index)
  836.           'End
  837.         End If
  838.       Else
  839.         'the user can't delete files
  840.         retf = send_reply("550 You can't take this file action.", FTP_Index)
  841.       End If
  842.     Else
  843.       retf = send_reply("530 User not logged in.", FTP_Index)
  844.     End If
  845.   
  846.   Case "MKD", "XMKD" 'MKD <pathname>
  847.     If users(FTP_Index).State = 2 Then
  848.       PathName = ChkPath(FTP_Index, FTP_Args(0))
  849.       'controls access rights
  850.       'DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(1).Accs
  851.       'If InStr(DummyS, "M") Then
  852.       DirFnd = False
  853.       For i = 1 To UserIDs.No(users(FTP_Index).list_index).Pcnt
  854.         If UserIDs.No(users(FTP_Index).list_index).Priv(i).Path = PathName Then
  855.         'To do drive letter permissions use this line
  856.         'If Left(UserIDs.No(users(FTP_Index).list_index).Priv(i).Path, 2) = Drv Then
  857.           DummyS = UserIDs.No(users(FTP_Index).list_index).Priv(i).Accs
  858.           DirFnd = True
  859.           Exit For
  860.         End If
  861.       Next
  862.   
  863.       If InStr(DummyS, "M") And DirFnd Then
  864.         'the user can updates files
  865.         MkDir PathName
  866.         If Err.Number = 0 Then
  867.           'the directory is been created
  868.           retf = send_reply("257 " & FTP_Args(0) & " created.", FTP_Index)
  869.         ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  870.           'the directory isn't been created
  871.           retf = send_reply("550 MKD command not executed: " & Error$, FTP_Index)
  872.         Else
  873.      '     frmFTP.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  874.           retf = logoff(FTP_Index)
  875.           'End
  876.         End If
  877.       Else
  878.         'the user can't write on files
  879.         retf = send_reply("550 You can't take this file action.", FTP_Index)
  880.       End If
  881.     Else
  882.       retf = send_reply("530 User not logged in.", FTP_Index)
  883.     End If
  884.   
  885.   Case "PWD", "XPWD" 'PWD
  886.     If users(FTP_Index).State = 2 Then
  887.       PathName = users(FTP_Index).cur_dir
  888.       'Who doesn't want to know the the drive they are on?
  889.       'PathName = Right$(PathName, Len(PathName) - 2)
  890.       retf = send_reply("257 """ & PathName & """ is the current directory.", FTP_Index)
  891.     Else
  892.       retf = send_reply("530 User not logged in.", FTP_Index)
  893.     End If
  894.   
  895.   Case "LIST", "NLST"   'LIST <pathname>Or InStr(FTP_Args(0), "-L")
  896.       LIST_NLST FTP_Index, FTP_Command, FTP_Args(0)
  897.     
  898.   Case "STAT"  'STAT <pathname>
  899.       retf = send_reply("200 Not Implemented..", FTP_Index)
  900.   Case "HELP"  'HELP <string>
  901.     DummyS = "214-This is the list of recognized FTP commands:"
  902.     retf = send_reply(DummyS, FTP_Index)
  903.       DummyS = "214-   USER  PASS  CWD   XCWD  CDUP  XCUP  QUIT  PORT" & vbCrLf _
  904.              & "214-   PASV  TYPE  STRU  MODE  RETR  STOR  RNFR  RNTO" & vbCrLf _
  905.              & "214-   DELE  RMD   XRMD  MKD   XMKD  PWD   XPWD" & vbCrLf _
  906.              & "214    LIST  NLST  SYST  STAT  HELP  NOOP"
  907.     retf = send_reply(DummyS, FTP_Index)
  908.   
  909.   Case "NOOP" 'NOOP
  910.     retf = send_reply("200 NOOP command executed.", FTP_Index)
  911.   Case ""
  912.     Thread.SendMessage "error with ftpCommand"
  913.   Case Else
  914.     retf = send_reply("200 Not Implemented.." & FTP_Command, FTP_Index)
  915.   End Select
  916. Exit Function
  917. FileError:
  918.   Close #FTP_Index    'close file
  919.   retf = send_reply("550 RETR command not executed. File Error", FTP_Index)
  920.   retf = close_data_connect(FTP_Index)    'close data connection
  921. End Function
  922. Public Sub StartTimer()
  923.   mlngTimerID = SetTimer(0, 0, 100, AddressOf TimerProc)
  924. End Sub
  925. Private Sub TimerProc(ByVal hWnd As Long, ByVal msg As Long, _
  926.                       ByVal idEvent As Long, ByVal curTime As Long)
  927. 'Thread.SendMessage "Timer Fired"
  928.   StopTimer
  929.   FTP_Cmd2
  930. End Sub
  931. Public Sub StopTimer()
  932.   If mlngTimerID > 0 Then
  933.     KillTimer 0, mlngTimerID
  934.     mlngTimerID = 0
  935.   End If
  936. End Sub
  937. Public Sub KillThread()
  938.   Set Thread = Nothing
  939. End Sub